作者注:该系列文章基于《java线程设计模式》撰写,只用于学习和交流。
含义:多线程运行,当前线程没有达到警戒条件时,线程会进入等待直到被唤醒,该模式被称为Guarded Suspension pattern模式。
其顺序图如下:
代码示例
Request 类,请求封装的实体类,这是设计模式中很常见的方式,这样有利于承载及存储。
package pattern.guard.suspension;
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 + '\'' +
'}';
}
}
RequestQueue,请求对象的承载类,内部实现使用了链表。
package pattern.guard.suspension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.LinkedList;
public class RequestQueue {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final LinkedList queue=new LinkedList();
public synchronized Request getQueue(){
while(queue.size()<=0){
try{
wait();
}catch (InterruptedException e){
log.error(e.getMessage());
}
}
return queue.removeFirst();
}
public synchronized void putRequest(Request request){
queue.addLast(request);
notifyAll();
}
}
ClientThread,用于生成请求对象的线程类。
package pattern.guard.suspension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
public class ClientThread extends Thread {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private Random random;
private RequestQueue requestQueue;
public ClientThread(RequestQueue requestQueue,String name,long seed){
super(name);
this.requestQueue=requestQueue;
this.random=new Random(seed);
}
@Override
public void run(){
for (int i = 0; i < 10000; i++) {
Request request=new Request("No."+i);
System.out.println(Thread.currentThread().getName()+" request"+request);
requestQueue.putRequest(request);
try{
Thread.sleep(random.nextInt(1000));
}catch(Exception e){
log.error(e.getMessage());
}
}
}
}
ServerThread,请求服务类,处理业务逻辑的地方。
package pattern.guard.suspension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
public class ServerThread extends Thread{
private final Logger log = LoggerFactory.getLogger(this.getClass());
private Random random;
private RequestQueue requestQueue;
public ServerThread(RequestQueue requestQueue,String name,long seed){
super(name);
this.requestQueue=requestQueue;
this.random=new Random(seed);
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
Request request= requestQueue.getQueue();
System.out.println(Thread.currentThread().getName()+" request"+request);
try{
Thread.sleep(random.nextInt(1000));
}catch(Exception e){
log.error(e.getMessage());
}
}
}
}
main测试类
package pattern.guard.suspension;
public class Main {
public static void main(String[] args){
RequestQueue queue=new RequestQueue();
new ClientThread(queue,"Alice",3141592L).start();
new ServerThread(queue,"Bobby",6525293L).start();
}
}
代码解读:
putRequest:往队列中存放一个请求,然后唤醒该对象所有的等待集。
getRequest:从队列中取出第一条请求,其警戒条件为while(queue.size()<=0),当线程达到这个条件时会进入该对象等待集并释放线程持有的对象锁,这就是guarded suspension-防卫阻止的意思。
测试结果:
Alice requestRequest{name='No.0'}
Bobby requestRequest{name='No.0'}
Alice requestRequest{name='No.1'}
Bobby requestRequest{name='No.1'}
Alice requestRequest{name='No.2'}
Bobby requestRequest{name='No.2'}
Alice requestRequest{name='No.3'}
Bobby requestRequest{name='No.3'}
Alice requestRequest{name='No.4'}
Bobby requestRequest{name='No.4'}
。。。
SUCCESS.
等待端:
while(!ready){
wait();
}
唤醒端:
ready=true;
notifyAll();
上面的程序属于这种,下面展示几种变形。
等待端:
while(!ready){
Thread.yield();
}
唤醒端:
ready=true;
这种称为"忙碌的等待",不适用wait(),尽可能将优先级交给其他线程,并不断测试条件。
旋转而锁定,表现为当条件成立前不断旋转。