スレッドデザインパターン - Gurded Suspentation
Conditionを使って3章の「Gurded Suspentation」を書いてみた。
このサンプルは、ClientThreadがRequestを出して、ServerThreadがRequestを非同期に処理する、というもの。Requestの一時置き場にRequestQueueを使っている。
ちなみにこのRequestQueueは、実際にはBlockingQueue
ClientThread, ServerThreadが複数になるバージョンは5章の「Producer-Consumer」になる。
また、ClientThread, ServerThreadが同期してRequestを処理するときは、Exchanger
Main.java
package dp.chap03; public class Main { public static void main(String[] args) throws Exception { RequestQueue requestQueue = new RequestQueue(); new ClientThread(requestQueue, "Alice").start(); new ServerThread(requestQueue, "Bobby").start(); } }
Request.java
package dp.chap03; public class Request { private final String name_; public Request(String name) { name_ = name; } public String getName() { return name_; } public String toString() { return "[Request " + getName() + " ]"; } }
ClientThread.java
package dp.chap03; import java.util.*; public class ClientThread extends Thread { private Random random_ = new Random(); private RequestQueue requestQueue_; public ClientThread(RequestQueue requestQueue, String name) { super(name); requestQueue_ = requestQueue; } public void run() { for(int i=0; i<10000; ++i) { Request request = new Request("No." + i); System.out.println(Thread.currentThread().getName() + " requests " + request); requestQueue_.putRequest(request); try { sleep(random_.nextInt(1000)); } catch(InterruptedException ie) {} } } }
ServerThread.java
package dp.chap03; import java.util.*; public class ServerThread extends Thread { private Random random_ = new Random(); private RequestQueue requestQueue_; public ServerThread(RequestQueue requestQueue, String name) { super(name); requestQueue_ = requestQueue; } public void run() { for(int i=0; i<10000; ++i) { try { Request request = requestQueue_.getRequest(); System.out.println(Thread.currentThread().getName() + " handles " + request); sleep(random_.nextInt(1000)); }catch(InterruptedException ie) { return; } } } }
RequestQueue.java
package dp.chap03; import java.util.*; import java.util.concurrent.locks.*; public class RequestQueue { private final LinkedList<Request> queue_ = new LinkedList<Request>(); private Lock mutex_ = new ReentrantLock(); private Condition notEmpty_ = mutex_.newCondition(); public Request getRequest() throws InterruptedException { mutex_.lock(); try { while(queue_.isEmpty()) { notEmpty_.await(); } return queue_.removeFirst(); }finally { mutex_.unlock(); } } public void putRequest(Request request) { mutex_.lock(); try { queue_.addLast(request); notEmpty_.signalAll(); }finally { mutex_.unlock(); } } }
実行結果がこれ↓
Alice requests [Request No.0 ] Bobby handles [Request No.0 ] Alice requests [Request No.1 ] Bobby handles [Request No.1 ] Alice requests [Request No.2 ] Alice requests [Request No.3 ] Alice requests [Request No.4 ] Bobby handles [Request No.2 ] Bobby handles [Request No.3 ] Alice requests [Request No.5 ] Alice requests [Request No.6 ] Bobby handles [Request No.4 ] Bobby handles [Request No.5 ] Alice requests [Request No.7 ] Alice requests [Request No.8 ] Alice requests [Request No.9 ] Bobby handles [Request No.6 ] Alice requests [Request No.10 ] Bobby handles [Request No.7 ] Bobby handles [Request No.8 ] Bobby handles [Request No.9 ] Alice requests [Request No.11 ] Alice requests [Request No.12 ] Bobby handles [Request No.10 ] Bobby handles [Request No.11 ] Alice requests [Request No.13 ] Bobby handles [Request No.12 ]