1. 程式人生 > >多線程系列之四:Guarded Suspension 模式

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

ted override 角色 str lis current bsp ride 安全性

一,什麽是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 模式