一、定义
guarded是“被保护着的”、“被防卫着的”意思,suspension则是“暂停”的意思。当现在并不适合马上执行某个操作时,就要求想要执行该操作的线程等待,这就是Guarded Suspension Pattern。
Guarded Suspension Pattern 会要求线程等候,以保障实例的安全性,其他类似的称呼还有guarded wait,spin lock等。
二、模式案例
下面的案例是一种简单的消息处理模型,客户端线程发起请求,有请求队列缓存请求,然后发送给服务器进行处理。
request.java
package Entity;
public class Request {
private final String name;
public Request(String name) {
this.name = name;
}
@Override
public String toString() {
return "Request{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
}
RequestQueue.java
package Entity;
import java.util.LinkedList;
public class RequestQueue {
private final LinkedList<Request> queue = new LinkedList<Request>();
public synchronized Request getRequest(){
while (queue.size() <= 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return queue.removeFirst();
}
public synchronized void putRequeest(Request request) {
queue.add(request);
notify();
}
}
注:getRequest方法中有一个判断while(queue.size() <= 0),该判断成为Guarded Suspension Pattern的警戒条件(Guarded condition)。
ClientThread.java
package Entity;
import java.util.Random;
public class ClientThread extends Thread {
private Random random;
private RequestQueue requestQueue;
public ClientThread(String name, long seed, RequestQueue requestQueue) {
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("No." + i);
System.out.println(Thread.currentThread().getName() + " requests" + request);
requestQueue.putRequeest(request);
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ServerThread.java
package Entity;
import java.util.Random;
public class ServerThread extends Thread{
private Random random;
private RequestQueue requestQueue;
public ServerThread(String name, long seed, RequestQueue requestQueue) {
super(name);
this.random = new Random(seed);
this.requestQueue = requestQueue;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
Request request = requestQueue.getRequest();
System.out.println(Thread.currentThread().getName() + " handles " + request);
try {
Thread.sleep(random.nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
main.java
import Entity.ClientThread;
import Entity.RequestQueue;
import Entity.ServerThread;
public class Demo3 {
public static void main(String[] args) {
RequestQueue requestQueue = new RequestQueue();
new ClientThread("Alice",3141592L,requestQueue).start();
new ServerThread("Bobby",6535897L,requestQueue).start();
}
}
三、模式讲解
角色:
Guarded Suspension Pattern 角色如下:
- GuardedObject(被防卫的)参与者
GuardedObject参与者是一个拥有被防卫的方法(guardedMethod)的类。当线程执行guardedMethod时,只要满足警戒条件,就能继续执行,否则线程会进入wait set区等待。警戒条件是否成立随着GuardedObject的状态而变化。
GuardedObject参与者除了guardedMethod外,可能还有用来更改状态的方法statueChangingMethod。
在Java语言中,是使用while语句和wait方法来实现guardedMethod;使用notify/notifyAll方法实现statueChangingMethod。如案例中的RequestQueue类。
注意:Guarded Suspention Pattern需要使用while,这样可以使从wait set被唤醒的线程在继续向下执行前检查Guard条件。如果改用if,当多个线程被唤醒时,由于wait是继续向下执行的,可能会出现问题。