《图解Java多线程设计模式》之四: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; } }