java多线程设计模式之Guarded Suspension

想象一个场景,你在排队领军训的装备,当你排队到窗口的时候,工作人员对你说,等一下,让我叫后勤先去仓库取下装备再给你,于是你等到工作人员取回装备才能领走装备。
抽象为一个java程序模型:你是一个线程ClientThread,负责取数据Request,暂时存放装备的窗口是一个队列RequestQueue,后勤人员是一个存放装备的线程ServerThread,于是可以用一下代码表示:
首先是存放数据到队列的线程类ClientThread:

public  static class ClientThread extends Thread{
		private RequestQuue requestQuue;

		public ClientThread(RequestQuue requestQuue,String name) {
			super(name);
			this.requestQuue = requestQuue;
		}
		
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 1000; i++) {
				Request request = new Request("request"+i);
				requestQuue.putRequest(request);
				System.out.println(Thread.currentThread().getName()+"   put    "+request.getName());
				try {
					sleep(new Random().nextInt(200));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
	}

然后是取数据的线程类ServerThread:


public static class ServerThread extends Thread{
		private RequestQuue requestQuue;

		public ServerThread(RequestQuue requestQuue,String name) {
			super(name);
			this.requestQuue = requestQuue;
		}
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 1000; i++) {
				Request request = requestQuue.getRequest();
				System.out.println(Thread.currentThread().getName()+"   get   "+request.getName());
				try {
					sleep(100);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}


这里故意让取得速度比存放快,才容易出现等待状态。


这是任务类Request:

public class Request {
	private String name;

	public Request(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public String toString() {
		// TODO Auto-generated method stub
		return name;
	}
}


核心类RequestQueue:


public class RequestQuue {
	private final LinkedList queue = new LinkedList();
	public synchronized Request getRequest(){
		while (queue.size() <= 0) {
			try {
				wait();

			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
		return (Request) queue.removeFirst();
	}
	
	public synchronized void putRequest(Request requst) {
		// TODO Auto-generated method stub
		queue.addLast(requst);
		notifyAll();
	}
}

看到中间这一段:


while (queue.size() <= 0) {
			try {
				wait();

			} 

这是今天的重点,就像你要取装备的时候工作人员告诉你暂时没装备,等后勤把装备取来一样,你总不能砸窗去里面抢吧?这是对于RequestQueue的保护,防止出现没数据却仍然执行getRequest导致出现java.util.NoSuchElementException异常。
wait方法是Object的方法,作用是使已经获取一个对象锁的线程进入等待状态,并释放自己的对象锁,此时如果有其他线程在等待,则会竞争这把锁以执行代码。
看下putRequest中,当存入一个Request的时候,执行了notifyAll方法,这也是Object的方法,作用是唤醒正在当前线程持有的对象锁上wait的所有线程(notify则是随机唤醒一个线程),这样相当于后勤将装备取过来,大叫一声:“可以拿装备了!”。于是之后wait的getRequest线程被唤醒,开始取数据。
注意,wait外围要加一层循环判断,这是因为线程在wait有可能在不执行notyfy/notifyAll方法的情况下醒来,为了保险要加一个循环判断。
这就是一个最简单的生产者消费者的模型,一个线程生产数据,另一个线程消费数据,消费数据的线程如果遇到没数据的情况下,则等待数据的出现再执行。

发布了69 篇原创文章 · 获赞 76 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/sinat_23092639/article/details/52892094
今日推荐