多线程系列之四:Guarded Suspension 模式

Posted inspred

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多线程系列之四: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 模式的主要内容,如果未能解决你的问题,请参考以下文章

实战并发编程 - 09多线程Guarded Suspension模式案例实战

多线程编程-设计模式之保护性暂挂(Guarded Suspesion)模式

JVM故障分析系列之四:jstack生成的Thread Dump日志线程状态

实战并发编程 - 08基于Guarded Suspension模式优化轮询while(true)

Android多线程分析之四:MessageQueue的实现

JVM系列之四:运行时数据区