线程通信

  线程同步中有说用同步方法、同步代码块、lock锁实现线程同步,但有时候仅仅是同步还满足不了需求。例如,一个售票系统,分打印车票和售出车票两个线程,当无票时,要打印车票后才能售票,有票时直接售出。这样,两个线程之间就需要相互通信。

        对于由synchronized修饰的同步方法和同步代码块,我们可以借助Thread类提供的wait()/notify()/notifyAll()三个方法来实现线程间通信。这三个方法必须由同步监视对象调用,这可以分为两种情况:

        1.对于使用synchronized修饰的同步方法,同步对象就是this(默认实例),所以可以在同步方法内直接调用者三个方法。

        2.对于使用synchronized修饰的同步代码块,同步对象是synchronized后括号里的对象,所以要使用这个对象调用这三个方法。

      关于这三个方法的解释如下:

       wait():导致当前线程等待,直到其他线程使用notify或notifyAll唤醒该线程。调用wait()方法的当前线程释放对同步监视器的锁定。wait()方法有三种形式:无参方法,要一直等待下去直到线程被唤醒;带有毫秒级或毫秒级、微秒级时间参数的wait(),线程等待指定的时间后自动苏醒。

       notify():唤醒在此同步监视器上等待的单个线程。如果所有线程都在此同步监视器上等待,则会选择唤醒其中一个线程,这种选择是任意性的。只有当前线程释放了同步监视器以后才可以唤醒其他线程。

       notifyAll():唤醒在此同步监视器上等待的所有线程。

     下面我们用wait和notify方法来实现售票程序的编程。代码如下:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Tickets {
	private final Lock lock=new ReentrantLock();
	private final Condition cond=lock.newCondition();
	int size;  //总票数    
    static int number=0;  //票号
    boolean available=false; //是否有票,一开始无票
    public Tickets(int size){
    	this.size=size;   
    } 
    public static void main(String args[]){
		Tickets t=new Tickets(3);
		//System.out.println("111");
	    new Producer(t).start();
	   // new Consumer(t).start(); 
	    System.out.println("2222");

	}
    //印票
   public  void put(){  
	  lock.lock();	 
      try {
    	//如果还有存票则印票线程等待
    	  if(available){
    		  cond.await(); 
	    	  System.out.println("\n当前没有票!");
	          number++;
	          System.out.println("印刷第"+number+"号票");
	          cond.signal();
	          //唤醒售票线程
	          notify(); 
    	  }
      }
	  catch(Exception e){
		  e.printStackTrace();
	  }
     
      finally{
    	  lock.unlock();
      }
  
   } 
	//售票
	  public synchronized void sell(){ 
		  System.out.println("进入sell");
		  lock.lock();
		//如果没有存票,则售票线程等待
	      try {
	    	  System.out.println("进入try");
	    	  if(!available) {
	    		  System.out.println("进入available");
	    		  cond.await();
		    	  System.out.println("\n当前有票...");
			      System.out.println("售出第"+number+"张票");
			      available=false;   
			      cond.signal();
			      if(number==size) number=size+1;
	    	  }
	      }
		  catch(Exception e){
			  e.printStackTrace();
		  }
	     
	      finally{
	    	  lock.unlock();
	      }
	  }
}

class Producer extends Thread{   
	Tickets t=null;
    public Producer(Tickets t){
    	this.t=t;   
    }
    public void run(){
    	while(t.number<t.size) 
    	t.put();      
    }
}

class Consumer extends Thread{  
	Tickets t=null;
     public Consumer(Tickets t){ 
    	 this.t=t; 
     }
    public void run(){    
    	while(t.number<=t.size) 
    	t.sell();   
    }
}


        如果程序不使用synchronized关键字来保证同步不,而是直接使用lock锁来保证同步,系统版中不存在隐式的同步监视器对象,也就不能用wait、nontify、notifyAll来进行线程间通信。对于使用lock锁的线程,java使用Condition类来保证同步。Condition将同步监视器方法分成三个截然不同的对象,以便通过将这些对象与lock对象组合使用,来控制同步。在这种情况下,lock代替了同步代码块或同步方法,Condition代替了同步监视器。

        Condition实例实质上被绑定在一个lock对象上。要获得特定的lock实例的Condition实例,调用lock的newCondition方法即可。Condition提供了三个方法:

         await:相当于wait()

         signal:相当于notify

         signalAll:相当于notifyAll

  同样是售票程序,我们用Condition来实现,其代码如下:

   

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Tickets {
	private final Lock lock=new ReentrantLock();
	private final Condition cond=lock.newCondition();
	int size;  //总票数    
    static int number=0;  //票号
    boolean available=false; //是否有票,一开始无票
    public Tickets(int size){
    	this.size=size;   
    } 
    public static void main(String args[]){
		Tickets t=new Tickets(3);
	    new Producer(t).start();
	    new Consumer(t).start(); 
	   

	}
    //印票
   public  void put(){  
	  lock.lock();	 
      try {
    	//如果还有存票则印票线程等待
    	  if(!available){
	    	  System.out.println("\n当前没有票!");
	          number++;
	          System.out.println("印刷第"+number+"号票");
	          available=true; 
	          //唤醒售票线程
	          cond.signal();
    	  }else{
    		  cond.await(); 
    	  }
      }
	  catch(Exception e){
		  e.printStackTrace();
	  }
     
      finally{
    	  lock.unlock();
      }
  
   } 
	//售票
	  public synchronized void sell(){ 
		  lock.lock();
		//如果没有存票,则售票线程等待
	      try {
	    	  if(available) {
		    	  System.out.println("\n当前有票...");
			      System.out.println("售出第"+number+"张票");
			      available=false;   
			      cond.signal();
			      if(number==size) number=size+1;
	    	  }else{
	    		  cond.await();
	    		 
	    	  }
	      }
		  catch(Exception e){
			  e.printStackTrace();
		  }
	     
	      finally{
	    	  lock.unlock();
	      }
	  }
}

class Producer extends Thread{   
	Tickets t=null;
    public Producer(Tickets t){
    	this.t=t;   
    }
    public void run(){
    	while(t.number<t.size) 
    	t.put();      
    }
}

class Consumer extends Thread{  
	Tickets t=null;
     public Consumer(Tickets t){ 
    	 this.t=t; 
     }
    public void run(){    
    	while(t.number<=t.size) 
    	t.sell();   
    }
}


  java中还有一种实现同步的机制:使用管道流。不过,这种方式多用在进程间通信,线程之间很少使用。等以后用到进程间通信再学习吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值