Java多线程设计模式详解学习笔记五——GuardedSuppension

本文探讨了并发编程中的线程同步与通信机制,通过分析一个简单的多线程应用,展示了请求队列如何在客户端线程与服务端线程间进行数据交换,以及wait/notify机制在协调线程活动中的作用。
public class Main {
	public static void main(String[] args) {
	    RequestQueue requestQueue=new RequestQueue();
	    new ClientThread("Alice",requestQueue,  3141592L).start();
	    new ServerThread("Bobby",requestQueue,  6535897L).start();
	}
}
public class Request {
	private final String name;
	
	public Request(String name) {
		this.name=name;
	}
	
	@Override
	public String toString() {
		return "[ Request "+name+"]";
	}
}
public class RequestQueue {
	private final LinkedList<Request> queue=new LinkedList<Request>();
	
	public synchronized Request getRequest() {
		if (queue.size()<=0) {
			try {
				wait();//this.wait();当前执行的线程在this上等待,也就是在RequestQueue实例对象上面等待
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return queue.removeFirst();
	}
	
	public synchronized void putRequest(Request request) {
	      queue.addLast(request);
	      notifyAll();
	}
}
public class ClientThread extends Thread{
	
	private Random random;
	private RequestQueue requestQueue;
	
	public ClientThread(String name,RequestQueue requestQueue,long seed) {
		super(name);
		this.requestQueue=requestQueue;
		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() + " requests " + request);
			requestQueue.putRequest(request);
			try {
				Thread.sleep(random.nextInt(1000));
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}
public class ServerThread extends Thread{
	private Random random;
	private RequestQueue requestQueue;
	
	public ServerThread(String name,RequestQueue requestQueue,long seed) {
		super(name);
		this.requestQueue=requestQueue;
		random=new Random(seed);
	}
	
	@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) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}

运行结果:

Alice requests [ Request No.0]
Bobby handles [ Request No.0]
Alice requests [ Request No.1]
Alice requests [ Request No.2]
Bobby handles [ Request No.1]
Bobby handles [ Request No.2]
Alice requests [ Request No.3]
Bobby handles [ Request No.3]
Alice requests [ Request No.4]
Bobby handles [ Request No.4]
Alice requests [ Request No.5]
Alice requests [ Request No.6]
Bobby handles [ Request No.5]
Bobby handles [ Request No.6]
Alice requests [ Request No.7]
Bobby handles [ Request No.7]
Alice requests [ Request No.8]
Bobby handles [ Request No.8]
Alice requests [ Request No.9]
Bobby handles [ Request No.9]
Alice requests [ Request No.10]
Alice requests [ Request No.11]
Bobby handles [ Request No.10]
Bobby handles [ Request No.11]
执行wait等待条件的变化:

执行wait的时候,线程是在等待什么?线程真正所等待的,是实例状态的变化。等待中的线程,正等待着警戒条件的变化。

只有了解“线程在等待什么”,就知道何时应该“调用notify/notifyAll”,也就是说在等待的东西完成的地方调用notify/notifyAll

wait与锁定:

当某个线程试图去执行某个实例的wait方法时,这个线程必须获取改实例的锁定。在synchronized方法中调用wait方法,在执行wait的时候,的确线程正获取this的锁定 。然而当线程执行this的wait方法后,会进入wait的等待区,这时,线程就会解除this的锁定。而线程可能会因为notify、notifyAll、或interrupt退出等待区。不过在实际执行下一个语句之前,必须再次获得this的锁定才行。

wait与notify、notifyAll的责任(复用性):

程序中只有RequestQueue类有用到wait/notifyAll,在ClientThread、ServerThread、Main等其他类中都没有出现wait/notifyAll。Guarded Suspension Pattern的实现是封装在RequestQueue类里的。之所以隐藏wait/notifyAll,是为了RequestQueue类的复用性。使用RequestQueue类的一方,并不需要考虑wait/notifyAll的问题,只要调用getRequest方法与putRequest方法就行了。

guarded wait:

意义是“被阻挡而等待”,线程使用wait等待,等到被notify/notifyAll再次测试条件的实例方法。使用wait等待的时间,其实是停止在停止在等待区里停止执行,所以不会浪费java执行环境的处理时间。

等待端的范例:

while(!ready)

{
     wait();
}
唤醒端范例:

ready=true;
notifyAll;
busy wait:

“忙碌等待”的意思,线程不适用wait等待,而是用yield(进可能把优先级让给其他线程),并不断测试条件的方法。因为等待中的线程也持续运行着,所以会浪费java虚拟机的时间。yield是Thread累的类方法。

等待端的范例:

while(!ready){
    Thread.yield();
}
唤醒端的范例:

ready=true;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值