Java线程间的通信

线程间的通信



1、当任务相互之间进行协作时, 关键问题是实现这些任务之间的握手,为了实现这种握手,可以使用任务相同的基础特性:互斥对于这些实现这些握手问题可以采用的方法:
①通过Object对象的wait()和notify()方法来安全实现
②通过SE5并发类库中Condition对象的await()和signal()方法;


2、Object的wait、notify方法

1)wait、notify和sleep、yield的区别
      ①wait()可以使一个任务被挂起, 对象上的锁被释放,而 sleep、yield调用时 对象上的锁不会被释放
      ②wait、notify是基于Object的,而sleep、yield是基于Thread的;
      ③wait、notify只能在synchronized同步控制方法、或同步控制块中调用(因为需要同步控制锁),sleep、yield可以在费同步控制块中调用;
2)wait(milliseconds):调用对象的锁被挂起milliseconds, 之后对象从wait中恢复;
     wait():调用对象的锁被释放,并无限等待下去,直到该对象调用了notify或notifyAll;
     notifyAll():将调用对象上全部被挂起的任务恢复运行;
     notify():将调用对象上一个被挂起的任务恢复,该任务的选择时任意,一般当多个任务使用相同的条件等待同一个锁,此时使用notify比起notifyAll效率更高;
3)示例代码
T1:
synchronized(sharedMonitor){
     <setup condition for T2>;
      sharedMonitor.notify();
}
T2:
synchronized(shareedMonitor){
     while(somwCondition){
          //point1;
          shareMonitor.wait();
     }
}
//T1是通知T2的线程,T2在运行是由于某种条件而挂起,而T1进行相应的处理后改变该条件,同时释放shareMonitor的锁,是T1恢复运行;
/*如果T2是以下的方式,可能会错失T1的通知,在T2 point1处,由T1处理后的条件状态可能已经被修改,从而可能会导致死锁
while(someCondition){
     //point1;
     synchronized(sharedMonitor)
          shareMonitor.wait();
}*/


实例:仿真延时多输线程输入开关(响应每一个任务):
class Light{
     private boolean switch = false;  //线程控制条件
     public void turnOn() throws InterruptedException{  //turn on switch
          synchronized(this){
               while(switch == true)
                    wait();
              
               TimeUnit.SECONDS.sleep(2);  //at lest run 3s;
               switch = true;
               notifyAll();
          }
     }
     public void trunOff() throws InterruptedException{  //turn off switch
          synchronized(this){
               while(switch == false)
                    wait();

               switch = true;
               notify();
          }
     }
}
//Test
class Demo{
     public static void main() throws InterruptedException {
          Switch lightSwitch = new Switch();
          Scanner input = new Scanner(System.in);
          ExecutorService exec = Executor.newCachedThreadPool();
          while(!Thread.interrupted()){
               in = nextBoolean();
               if(in){
                    exec.execute(new Runnable(){
                         public void run(){
                              lightSwitch.turnOn();
                     }});
               }
                   
               else if(!in){
                    exec.execute(new Runnable(){
                         public void run(){
                              lightSwitch.turnOff();
                     }});
               }
          }    
     }
}



     
3、Condition的await、signal操控Lock的行为

1)对lock绑定一个或多个Condition条件类,在不同的代码块中通过Condition来操作lock;
一个lock可以对应拥有多个condition,每个condition的状态对应各自的状态控制,共同决定lock的状态
2)使用lock的condition条件进行线程通信时注意要检测 InterruptedException异常;
3) signal( ):唤醒任意一个等待该条件的线程;
      signalAll( ):唤醒所有等待该条件的线程;
4)实例代码
class Demo {
 *   Lock lock = new ReentrantLock();
 *   Condition condition = lock.newCondition();
 *   public void method1(){
 *           lock.lock();
 *          try{
 *                while()
 *                   condition.await();
 *                statements;
 *          }catch( InterruptedException ex){
 *          }finally{
 *                 lock.unlock();
 *          }
 *    }
 *    public void method2(){   
 *           lock.lock();
 *          try{
 *                statements;
 *                 condition.signalAll();
 *          }finally{
 *                 lock.unlock();
 *          }
 *    }
 * } /*method1在条件不满时线程被挂起,对象锁释放,
      method2获取对象锁之后,进行相应的操作修改条件,并释放对象锁
      method1再次获取对象锁后,满足条件并执行之后的代码;*/

 
实例:仿真延时多输线程输入开关(响应每一个任务):
class Switch{
     Lock lock = new ReentrantLock();
     Condition condition = lock.newCondition();
     private boolean switch;
     public void turnOn(){
          lock.lock();
          try{
               while(switch == true)
                    condition.await();   
               
               TimeUnit.SECONDS.sleep(2);
               switch = true;
               condition.signalAll();
          }catch(InterruptException e){
          }finally{
               lock.unlock();
          }
     }
     public void turnOff(){
          lock.lock();
          try{
               while(switch == false)
                    condition.await();

               switch = false;
               condition.signalAll();
          }catch(InterruptException e){
          }finally{
               lock.unlock();
          }
     }  
}



4、阻塞队列BlockingQueue<T>

1)wait和notifyAll是以一种比较底层的方式解决任务互操作的问题, 可以使用java.util.concurrent.BlockingQueue同步队列这种更高抽象级别的方式来解决这样的问题;
2)BlockingQueue在任何时刻都只允许一个任务加入或删除元素时,即能维持线程同步BlockingQueue为线程安全的;
3)BlockingQueue的主要实现具体类:
    ①ArrayBlockingQueue:有界阻塞队列,当满队时,加入操作的任务会被阻塞,但队空时,删除操作的任务会被阻塞;
    ②LinkedBlockingQueue:无界阻塞队列;
4)BlockingQueue很适合用来实现生产者-消费者模型;
5)实例
//生产者-消费者模型
public class Producer implements Runnable{
     BlockingQueue<String> queue;
     public Producer(queue){ this.queue = queue;}
     public void run(){
          try{
               <statements to product>
               String produce = ....;
               queue.put(produce);
         }catch(InterruptedException e){
              <statements while task is blocked> 
         }
     }
}
public class Consumer implements Runnable{
     BlockingQueue<String> queue;
     public Consumer(BlockingQueue<String> queue){ this.queue = queue}
     public void run(){
          try{
               String produce = queue.take();
               <statements to use produce>
          }catch(InterruptException e){
               <statements whlie the task is blocked>
          }
     }
}
public class Test{
     public static void main(){
          ExecuteService exec = Executors.newCachedThradPool();
          BlockingQueue<String> queue = new LinkedBlockingQueue();
          exec.execute(new Producer(queue));
          exec.execute(new Consumer(queue));
          exec.execute(new Consumer(queue));
          exec.shutdown();
     }
}




5、任务间使用管道进行输入/输出

1)在Java中 PipedWriter、PipedReader类库提供线程功能以“管道”的形式对线程间的输入/输出提供了支持;
PipedWriter:允许不同任务任务向管道写入;
PipedReader:允许不同任务从同一个管道读取;
2)示例代码:
import java,io.*;
class Sender implementouts Runnable{
     private PipedWriter out  = new PipedWriter();
     public void run(){
          while(true){
               out.write('A'+new Random().nextInt(26));
          }catch(IOException e){
          }catch(InterruptedException e){
          }
     }
}
class Receiver implements Runnable{
     private PipedReader in = new PipedReader();
     private static count;
     public void run(){
          while(true){
               char get = (char)in.read();
               System.out.println("Receiver "+ count++ +" Read:"+ get);
          }catch(IOException e){
          }catch(InterrupedException e){
          }
     }
}
class Test{
    public static void main(){
          ExecutorServcie exec = Executors.newCachedThreadPool();
          exec.execute(new Sender());
          exec.execute(new Revicer());
          exec.execute(new Revicer());
          TimeUnit.SECONDS.sleep(20);
          exec.shutdownNow();
     }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值