thread的wait\notify实现线程通信

背景:

之前的文章介绍过wait与sleep的区别,本文从另一个角度梳理一种实现线程通信的方式。

正文:

  wait()、notify()和notifyAll()是Object类中的方法:

  1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)

  3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

  4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;

为何这三个不是Thread类声明中的方法,而是Object类中声明的方法(当然由于Thread类继承了Object类,所以Thread也可以调用者三个方法)?其实这个问题很简单,由于每个对象都拥有monitor(即锁),所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。而不是用当前线程来操作,因为当前线程可能会等待多个线程的锁,如果通过线程来操作,就非常复杂了。

package thread;

public class NotifyTest {
	    public static Object object = new Object();
	    public static void main(String[] args) {
	        Thread1 thread1 = new Thread1();
	        Thread2 thread2 = new Thread2();	         
	        thread1.start();	         
	        try {
	            Thread.sleep(200);
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }	         
	        thread2.start();
	    }
	     
	    static class Thread1 extends Thread{
	        @Override
	        public void run() {
	            synchronized (object) {
	                try {
	                    object.wait();
	                } catch (InterruptedException e) {
	                }
	                System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
	            }
	        }
	    }
	     
	    static class Thread2 extends Thread{
	        @Override
	        public void run() {
	            synchronized (object) {
	                object.notify();
	                System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
<pre name="code" class="java"> <span style="white-space:pre">			</span>System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
} } }}
 运行结果如下: 


当然wait还有几个重载的方法设置超时时间:

public final void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException

导致线程进入等待状态直到它被通知或者经过指定的时间.

线面来看个常用的生产者消费者模式。模拟一个容器:

package thread;

import java.util.LinkedList;

public class Depository {
	 int capability = 5;  
	    private static LinkedList<Product> pool = new LinkedList();  
	    public LinkedList getPool() {  
	        return pool;  
	    }  
	    public synchronized int getSize() {  
	        return pool.size();  
	    }  
	    public synchronized boolean isEmpty() {  
	        return pool.isEmpty();  
	    }  
	    public synchronized boolean isFull() { 
	        if (this.getSize() == this.capability) {  
	            return true;  
	        } else {  
	            return false;  
	        }  
	    }
	    public synchronized void addLast(Product p) {  
	        this.notifyAll();  
	        if (!this.isFull()) {  
	            pool.addFirst(p);  
	            //System.out.println("当前线程的名称:" + Thread.currentThread().getName());  
	            System.out.println(Thread.currentThread().getName() + " 放入一个产品");  
	            System.out.println("仓库已经有 " + this.getSize() + " 个了");  
	             
	        } else {  
	            System.out.println("仓库满了,该线程" + Thread.currentThread().getName() + "等待");  
	      
	                try {
						wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}  	               
	        }
	    } 
	    
	    public synchronized Product remove(){
	    	
	    	if(!this.isEmpty()){//不为空,取出
	    	this.notifyAll();  //	
	    	Product p=	pool.removeFirst();	    
	    	return p;
	    	}else{//等待
	    		 System.out.println("仓库空了,该线程" + Thread.currentThread().getName() + "等待");  
	    		 try {
						wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}  	     
	    		 return null;
	    	}
	    }
}

package thread;

public class Product {

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public String toString(){
		return "product:"+this.name;
	}
}

package thread;
/**
 * 
 * @author zhangliang
 *
 * 2016年4月8日 下午1:57:32
 */
public class PCTest {

	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		PCTest test = new PCTest();
		Depository pool = new Depository();
		 Producer pro=test.new Producer(pool);
	        Consumer con=test.new Consumer(pool);
	      Thread p =  new Thread(pro);
	      Thread c1 =  new Thread(con);
	      Thread c2 =  new Thread(con);
	      p.start();
	      c1.start();
	      c2.start();
	        Thread.sleep(500);
	        p.interrupt();
	        c1.interrupt();
	        c2.interrupt();
	        
	}

	class Consumer implements Runnable{
	    //消费者线程拥有的资源
	    private Depository pool=null;
	    //构造函数
	    public Consumer(Depository pool)
	    {
	        this.pool=pool;
	    }
	    volatile boolean flag=true;
	    @Override
	    public void run() {
	       while(flag){
	            try {
	                Thread.sleep(100);
	            } catch (InterruptedException e) {	             
	                flag =false;
	            }
	            Product p =	 this.pool.remove();
	            if(p!= null)
	            {
	            	System.out.println("线程"+Thread.currentThread().getName()+"消费了"+p.toString());
	            }
	        }
	    }
	}
	
	//生产者线程
	class Producer implements Runnable{
	    //生产者线程拥有的资源
	    private Depository pool=null;
	    //构造函数
	    public Producer(Depository pool)
	    {
	        this.pool=pool;
	    }
	   
	    @Override
	    public void run() {
	        boolean flag=false;
	        while(true)
	      	{
	        	if(!pool.isFull())
	        	{
	            	Product p  = new Product();
	            	p.setName("p:"+System.currentTimeMillis());
	                this.pool.addLast(p);
	                try {
						Thread.sleep(10);
					} catch (InterruptedException e) {					
						flag =false;
					}
	        	}   
	        } 
	    }
	}
	
}

运行结果如下:

Thread-0 放入一个产品
仓库已经有 1 个了
Thread-0 放入一个产品
仓库已经有 2 个了
Thread-0 放入一个产品
仓库已经有 3 个了
Thread-0 放入一个产品
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150363
Thread-0 放入一个产品
仓库已经有 4 个了
线程Thread-1消费了product:p:1460095150373
Thread-0 放入一个产品
仓库已经有 5 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150443
线程Thread-1消费了product:p:1460095150536
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150546
Thread-0 放入一个产品
线程Thread-1消费了product:p:1460095150433
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-1消费了product:p:1460095150646
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150739
Thread-0 放入一个产品
仓库已经有 5 个了
线程Thread-2消费了product:p:1460095150749
线程Thread-1消费了product:p:1460095150636
Thread-0 放入一个产品
仓库已经有 4 个了
Thread-0 放入一个产品
仓库已经有 5 个了

1. 线程的等待或者唤醒,并不是让线程调用自己的wait或者notify方法,而是通过调用线程共享对象的wait或者notify方法来实现。
2. 线程要调用某个对象的wait或者notify方法,必须先取得该对象的监视器。
3. 线程的协作必须以线程的互斥为前提,这种协作实际上是一种互斥下的协作。

好了,本篇先到这里,下篇改用condition实现。




参考:

http://www.cnblogs.com/dolphin0520/p/3920385.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bohu83

买个馒头吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值