1,从名字上看就是增加了守护功能的一种设计模式,目的是确保在多线程条件下各线程能正常操作共享资源,如果触发了守护功能,相关的线程就必须等待,直到守护功能确保不会出现操作异常才会让线程继续执行下去。
2,与Single Threaded Execution 相似都是为了保护共享资源,只不过Single Threaded Execution是无条件的多线程互斥,而Guarded Suspension是在守护条件不满足的情况下才会使得相关的线程进入等待。
3,实现方式,这里有几个概念,一个是守护方法(GuardedMethod),该方法只有在守护条件满足的情况下才会执行对共享资源的操作,如果不满足守护条件,则让调用该方法线程一直等待,守护方法是通过while和wait实现。另一个是改变守护条件方法(StateChangeingMethod),该方法由另外一个线程调用,改变守护条件,使得守护方法里面能够满足守护条件,而让等待的线程继续执行下去,改变守护条件方法是通过notify/notifyAll来实现
4,代码实现
1)先定义一个Guard类,里面分别实现GuardedMethod和StateChangeingMethod,GuardedMethod的守护条件是共享资源的值等于5,如果不等于5就让当前线程一直等待
package guardesuspension.study;
public class Guard {
int sharedResource=0;
public synchronized void guardedMethod()
{
while(sharedResource!=5)
{
System.out.println("Thread name:"+Thread.currentThread().getName()+" is waiting");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread name:"+Thread.currentThread().getName()+" read shared resource:"+ sharedResource);
}
public synchronized void stateChangeingMethod()
{
sharedResource=5;
System.out.println("Thread name:"+Thread.currentThread().getName()+" set shared resource:"+ sharedResource);
notifyAll();
}
}
2)启动两条线程,线程1调用GuardedMethod,由于不满足守护条件,线程1被阻塞,2秒后,线程2调用stateChangeingMethod,改变共享资源的值,并且通知线程1,此时线程1的守护条件满足了,不再等待,继续执行下面的程序
package guardesuspension.study;
public class GuardedSuspension {
public static void main(String[] args) {
Guard guard=new Guard();
Thread thead1=new Thread(
new Runnable() {
@Override
public void run() {
guard.guardedMethod();
}
}
);
thead1.start();
Thread thead2=new Thread(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
guard.stateChangeingMethod();
}
}
);
thead2.start();
}
}
3)执行结果
Thread name:Thread-0 is waiting //线程0不满足守护条件,进入等待
Thread name:Thread-1 set shared resource:5 //线程1改变了守护条件,并通知线程0
Thread name:Thread-0 read shared resource:5 //此时线程0满足了守护条件不等待,执行等待后的程序
5,Java类库中的应用
java.util.LinkedBlockingQueue采用的就是Guarded Suspension模式
该类有两个相关方法
一个是take()获取队首元素,如果此时队列是空,那么调用take方法的线程就会进入等待。
一个是put ()往对列末尾添加元素,添加完后会让由于调用take进入等待的线程继续执行,获取到队首元素
LinkedBlockingQueue已经实现了线程等待功能,所以不需要使用wait, notify,notifyAll等线程同步方法
1)具体代码实例
package guardesuspension.study;
import java.util.concurrent.LinkedBlockingQueue;
public class LinkedBlockingQueueTest {
public static void main(String[] args) {
LinkedBlockingQueue<Integer> queue=new LinkedBlockingQueue<Integer>(100);
Thread thead1=new Thread(
new Runnable() {
@Override
public void run() {
try {
System.out.println("Thread name:"+Thread.currentThread().getName()+" Get first from quene");
int result= queue.take();
System.out.println("Thread name:"+Thread.currentThread().getName()+" Get first from quene the result="+result);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
);
thead1.start();
Thread thead2=new Thread(
new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println("Thread name:"+Thread.currentThread().getName()+" Put value to quene");
queue.put(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
);
thead2.start();
}
}
2)执行结果
Thread name:Thread-0 Get first from quene //线程0想获取队首元素,由于此时为空,线程进入等待
Thread name:Thread-1 Put value to quene //线程1把一个元素推入队列
Thread name:Thread-0 Get first from quene the result=100 //线程0继续执行,获取到队首元素