多線程系列之四:Guarded Suspension 模式
一,什麽是Guarded Suspension模式
如果執行現在的處理會造成問題,就讓執行處理的線程等待。這種模式通過讓線程等待來保證實例的安全性
二,實現一個簡單的線程間通信的例子
一個線程(ClientThread)將請求(Request)的實例傳遞給另外一個線程(ServerThread)
Request:線程實例
RequestQueue:存放請求(Request)實例的隊列
ClientThread:把線程實例放到隊列中
ServerThread:從隊列中取線程示例
示例程序
public class Request { private final String name;public Request(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Request{" + "name=‘" + name + ‘\‘‘ + ‘}‘; } }
public class RequestQueue {private Queue<Request> queue = new LinkedList<>(); public synchronized void putRequest(Request request){ queue.offer(request); notifyAll(); } public synchronized Request getRequest(){ while (queue.peek() == null){ try { wait(); }catch (InterruptedException e) { e.printStackTrace(); } } return queue.remove(); } }
public class ClientThread extends Thread { private final Random random; private final RequestQueue requestQueue; public ClientThread(RequestQueue requestQueue,String name ,long seed){ super(name); this.random = new Random(seed); this.requestQueue = requestQueue; } @Override public void run() { for (int i = 0; i < 10000; i++) { Request request = new Request("N0."+i); System.out.println(Thread.currentThread().getName()+" requests "+request); requestQueue.putRequest(request); try { Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class ServerThread extends Thread{ private final Random random; private final RequestQueue requestQueue; public ServerThread(RequestQueue requestQueue,String name,long seed){ super(name); this.random = new Random(seed); this.requestQueue =requestQueue; } @Override public void run() { for (int i = 0; i < 1000; i++) { Request request = requestQueue.getRequest(); System.out.println(Thread.currentThread().getName()+" handles "+request); try { Thread.sleep(random.nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Test { public static void main(String[] args) { RequestQueue requestQueue = new RequestQueue(); new ClientThread(requestQueue,"Alice",3141592L).start(); new ServerThread(requestQueue,"Bobby",6583184L).start(); } }
三,Guarded Suspension模式中的登場角色
GuardedObject:被守護的對象
GuardedObject是一個持有被守護的方法(guardedMethod)的類,當線程執行guardedMethod方法時,若守護條件成立,則可以立刻執行,
當守護條件不成立,就要進行等待。
守護條件的成立與否和被守護對象的狀態有關。
所以在上面的示例程序中
RequestQueue:就是被守護對象
getRequest方法:就是被守護方法
putRequest方法:改變狀態的方法
四,wait和notify/notifyAll的責任
上面的示例程序中,我們把wait/notifyAll都寫在了RequestQueue類中,並沒有出現在ClientThread,ServerThread,Main類中。
Guarded Suspension模式的實現封裝在RequestQueue類中。
這種將wait/notifyAll隱藏起來的做法對RequestQueue類的復用性非常重要。當我們在使用RequestQueue時,其他類無需考慮wait,notifyAll的問題,
只要調用getRequest方法或putRequst方法就行。
五,使用java.util.concurrent.LinkedBlockingQueue的示例程序
這個類和RequestQueue類功能相同。該類中的take方法用於 取出隊首元素,put方法則用於向隊列末尾添加元素。當隊列為空時,若調用take方法便會進行wait,
並且take和put已經考慮了互斥處理。所以getRequest和putRequest方法就無需聲明為synchronized了。LinkedBlockingQueue類中使用了Guarded Suspension模式。
代碼:
public class RequestQueue { private final BlockingQueue<Request> queue = new LinkedBlockingQueue<>(); public void putRequest(Request request){ try { queue.put(request); } catch (InterruptedException e) { e.printStackTrace(); } } public Request getRequest(){ Request request = null; try { request = queue.take(); } catch (InterruptedException e) { e.printStackTrace(); } return request; } }
多線程系列之四:Guarded Suspension 模式