LoginSignup
3
2

More than 5 years have passed since last update.

『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その5)

Last updated at Posted at 2017-02-27

javathread.jpeg

Guarded Suspensionパターン

Guarded Suspensionパターンにはguarded wait, spin lockなどの呼び名がある。

Request.java
public class Request {
     private final String name;
     public Request(String name) {
         this.name = name;
     }
     public String getName() {
         return name;
     }
     public String toString() {
         return "[ Request " + name + " ]";
     }
}
RequestQueue.java
import java.util.Queue;
import java.util.LinkedList;

public class RequestQueue {
    private final Queue<Request> queue = new LinkedList<Request>();
    public synchronized Request getRequest() {
        while (queue.peek() == null) {
            try {
                wait(); // キューが空の時は待つ(ウェイトセットに入る)
            } catch (InterruptedException e) {
            }
        }
        return queue.remove();
    }
    public synchronized void putRequest(Request request) {
        queue.offer(request);
        notifyAll(); // 待っているスレッドに、キューにrequestが入ったことを知らせる
    }
}
ClientThread.java
import java.lang.Math;

public class ClientThread extends Thread {
    private final RequestQueue requestQueue;
    public ClientThread(RequestQueue requestQueue, String name) {
        super(name);
        this.requestQueue = requestQueue;
    }
    public void run() {
        for (int i = 0; i <= 100; i++) {
            Request request = new Request("No." + i);
            System.out.println(Thread.currentThread().getName() + " put " + request);
            requestQueue.putRequest(request);
            try {
                Thread.sleep((int)(Math.random()*10));
            } catch (InterruptedException e) {
            }
        }
    }
}
ServerThread.java
import java.lang.Math; 

public class ServerThread extends Thread { 
    private final RequestQueue requestQueue; 
    public ServerThread(RequestQueue requestQueue, String name) { 
        super(name); 
        this.requestQueue = requestQueue; 
    } 
    public void run() { 
        for (int i = 0; i <= 100; i++) { 
            Request request = requestQueue.getRequest(); 
            System.out.println(Thread.currentThread().getName() + " get " + request); 
            try { 
                Thread.sleep((int)(Math.random()*10)); 
            } catch (InterruptedException e) { 
            } 
        } 
    } 
}
Main.java
public class Main { 
    public static void main(String[] args) { 
        RequestQueue requestQueue = new RequestQueue(); 
        new ClientThread(requestQueue, "A").start(); 
        new ServerThread(requestQueue, "B").start(); 
    } 
}
実行結果
...
A put [ Request No.95 ]
B get [ Request No.91 ]
B get [ Request No.92 ]
A put [ Request No.96 ]
A put [ Request No.97 ]
B get [ Request No.93 ]
A put [ Request No.98 ]
B get [ Request No.94 ]
A put [ Request No.99 ]
B get [ Request No.95 ]
B get [ Request No.96 ]
B get [ Request No.97 ]
B get [ Request No.98 ]
B get [ Request No.99 ]
...

ClientThreadがSeverThreadにRequestのインスタンスを受け渡す。これは非常に簡単なスレッド間通信。ClientThreadやServerThreadのことを能動オブジェクト、RequestQueueのことを受動オブジェクトと呼ぶ。

ClientThreadがQueueにリクエストを投げ(put)、ServerThreadがQueueからリクエストを取り出す(get)。putとgetはsynchronizedで排他されている。

getRequesメソッドは最も古いリクエストを一つ取り出す。リクエストが一つもない場合は、他のスレッドがputRequestするまで待つ。queue.peek() != nullという条件つまりQueueが空でないという条件が満たされている必要がある。このような、満たされていなければならない条件のことをGuarded Suspensionパターンのガード条件と呼ぶ。

putRequestメソッドは、リクエストを一つ追加する。その後notifyAllで待っているスレッドに知らせる。

waitとnotifyについては
『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その1)
を参照。

実行結果の通り、B(get)がA(put)を追い越すことはない。

登場人物

GuardedObject役は、ガードされたメソッド(guardedMethod)を持っているクラス。ガード条件が満たされていればすぐに実行され、満たされていなければ待たされる。GuardedObjec役は、インスタンスの状態を変化させるメソッド(stateChangingMethod)を持つ場合がある。サンプルプログラムではRequestQueueクラスがこの役をつとめ、getRequestがguardedMethod、putRequestがstateChangingMethodに対応する。


関連
『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その1)
『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その2)
『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その3)
『Java言語で学ぶデザインパターン(マルチスレッド編)』まとめ(その4)

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2