java#5 线程通信:线程的协调运行,条件变量,管道

一、线程的协调运行

       Object类提供了wait(),notify()和notifyAll()三种方法来实现线程之间的协调运行,但是

         这三种方法必须由同步监视器对象来调用。

         wait():导致当前线程等待,直到其它线程调用该同步监视器的notify()或者notifyAll()方法

                      来唤醒该线程。

         notify():唤醒在此同步监视器上等待的单个线程,如果有多个线程在此同步监视器上等待

                      选择唤醒其中一个线程,并且选择是任意的。

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

         代码示例:

         package defaultpackage;

         public class Account {
                private String accountNo;
                private double balance;
                //标示账户中是否已有存款的标志
                private boolean flag = false;
                public Account (){
                }
                public Account (String accountNo,double balance){
                       this.accountNo = accountNo;
                       this.balance = balance;
                }
                public double getBalance(){
                       return this.balance;
                }
                public synchronized void draw(double drawAmount){
                try{
                       //如果flag为假,表明账户中还没有人存钱进去,则取钱方法阻塞
                       if(!flag){
                              wait();
                       }
                       else{
                              //执行取钱
                              System.out.println(Thread.currentThread().getName()+

                              "取钱:"+drawAmount);
                              balance -= drawAmount;
                              System.out.println("账户余额为:"+balance);
                              //将标示账户是否有存款的标志设为flase
                              flag= false;
                              //唤醒其他线程
                              notifyAll();
                       }
               }catch(InterruptedException ex){
                       ex.printStackTrace();
                 }

         }
         public synchronized void deposit (double depositAmount){
                try{
                         //如果flag为真,表明账户中已有人存钱进去,则存钱方法阻塞
                         if(flag){
                                wait();
                         }
                         else{
                                //执行存款
                                System.out.println(Thread.currentThread().getName()+

                                "存款:"+depositAmount);
                                balance += depositAmount;
                                System.out.println("账户余额为:"+balance);
                                //将标示账户是否已有存款的标志设为true
                                flag = true;
                                //唤醒其它线程
                                notifyAll();
                         }
                }catch(InterruptedException ex){
                       ex.printStackTrace();
                  }
          }
          //此处省略了hashCode和equals两个方法
}

 

二、条件变量

       1、使用Lock对象来保持同步而不是使用synchronized关键字来保证同步,则系统

       中不存在同步监视器对象,不能使用wait,notify,notifyAll方法来协调进程的运行。

       2、在使用Lock对象保持同步时,java提供Condition类来保持协调;这样Lock替代

       了同步方法或同步代码块,Condition替代了同步监视器的功能。即将Condition对象

       绑定到一个Lock对象上,要获得特定Lock实例的Condition实例,调用Lock对象的

       newCondition()方法即可。Condition类提供如下三个方法:

       await():类似于wait()方法,导致当前线程等待,直到其他线程调用该Condition的

                     signal()方法或signslAll()方法来唤醒该线程。

       signal():唤醒在此Lock对象上等待的单个线程,若有多个线程等待,则唤醒其中

                    之一,选择是任意的。

       signalAll():唤醒在此Lock对象上等待的所有线程。

       代码示例:

       package defaultpackage;

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

       public class Account {
              //显示定义Lock对象
              private final Lock lock = new ReentrantLock();
              //获得指定Lock对象对应的条件变量
              private final Condition cond = lock.newCondition();
              private String accountNo;
              private double balance;
              //标示账户中是否已经有存款的标志
              private boolean flag = false;
              public Account(){}
              public Account(String accountNo,double balance){
                     this.accountNo = accountNo;
                     this.balance = balance;
              }
              public double getBalance(){
                     return this.balance;
              }
              public void draw(double drawAmount){
                     //加锁
                     lock.lock();
                     try{
                            //如果账户中还没有存入存款,该线程等待
                            if(!flag){
                                   cond.await();
                            }
                           else{
                                  //执行取钱操作
                                  System.out.println(Thread.currentThread().getName()+
                                         "取钱:"+drawAmount);
                                  balance -= drawAmount;
                                  System.out.println("账户余额为:"+balance);
                                  //将标示是否成功存入存款的标志设为false
                                  flag = false;
                                  //唤醒该Lock对象对应的其他线程
                                  cond.signalAll();
                           }
                     }catch(InterruptedException ex){
                            ex.printStackTrace();
                       }
                       //使用finally块来确保释放锁
                       finally{
                              lock.unlock();
                       }
            }
            public void deposit(double depositAmount){
                   lock.lock();
                   try{
                          //如果账户中已经存入了存款,该线程等待
                          if(flag){
                                 cond.await();
                          }
                          else{
                                 //执行存款操作
                                 System.out.println(Thread.currentThread().getName()+
                                        "存款:"+depositAmount);
                                 balance += depositAmount;
                                 System.out.println("账户余额为:"+balance);
                                 //将标示是否成功存入存款的标志设为true
                                 flag = true;
                                 //唤醒该Lock对象对应的其他线程
                                 cond.signalAll();
                           }
                   }catch(InterruptedException ex){
                                ex.printStackTrace();
                     }
                   //使用finally块来确保释放锁
                   finally {
                          lock.unlock();
                   }
            }
            //此处省略了hashCode和equals方法
      }

三、管道

             管道有3种存在形式:PipeInputStream和PipeOutputStream;PipedReader和PipedWriter;

          Pipe.SinkChannel和Pipe.SourceChannel,分别是管道字节流,管道字符流和新IO的管道Channel。

          用管道实现多线程通信的步骤如下:

          1、使用new  操作符分别创建管道输入流和管道输出流。

          2、使用管道输入流和管道输出流的connect方法把两个输入流和输出流连接起来。

          3、将管道输入流和管道输出流分别传入两个线程。

          4、两个线程可以分别依赖各自管道输入流、管道输出流进行通信。

          代码示例:

          package defaultpackage;

          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.PipedReader;
          import java.io.PipedWriter;

          public class ReaderThread {
                 private PipedReader pr;
                 //用于包装管道流的BufferReader对象
                 private BufferedReader br;
                 public ReaderThread(){}
                 public ReaderThread(PipedReader pr){
                        this.pr = pr;
                        this.br = new BufferedReader(pr);
                 }
                 public void run(){
                        String buf = null;
                        try{
                               //逐行读取管道输入流中的内容
                               while((buf = br.readLine())!=null){
                                      System.out.println(buf);
                                }
                        }
                        catch(IOException ex){
                                ex.printStackTrace();
                        }
                        //使用finally块来关闭输入流
                        finally{
                               try{
                                      if(br != null)
                                             br.close();
                               }catch(IOException ex){
                                        ex.printStackTrace();
                                }
                        }
                 }
          }
          public class WriteThread extends Thread{
                 String[] books = new  String[]{
                        "Structs2 权威指南",
                        "ROR敏捷开发指南",
                        "基于J2EE的Ajax宝典",
                        "轻量级J2EE企业应用指南"
                 };
                 private PipedWriter pw;
                 public WriterThread(){}
                 public WriterThread(PipedWriter pw){
                        this.pw = pw;
                 }
                 public void run(){
                        try{
                               //循环100次,向管道输出流中写入100个字符串
                               for(int i = 0;i<100;i++)
                                      pw.write(books[i%4] + "\n");
                        }catch(IOException ex){
                                ex.printStackTrace();
                         }
                       //使用finally块来关闭管道输出流
                       finally{
                              try{
                                     if(pw != null)
                                            pw.close();
                              }catch(IOException ex){
                                     ex.printStackTrace();
                               }
                        }
                 }

          }
          public class PipedCommunicationTest{
                 public static void main (String[] args){
                        PipedWriter pw = null;
                        PipedReader pr = null;
                        try{
                               //分别创建两个独立的管道输出流、输入流
                               pw = new PipedWriter();
                               pr = new PipedReader();
                               //连接管道输入流、输出流
                               pw.connect(pr);
                               //将连接好的管道分别传入两个线程
                               //就可以让两个线程通过管道流进行通信
                               new WriterThread(pw).start();
                               new ReaderThread(pr).start();
                       }catch(IOException ex){
                                ex.printStackTrace();
                         }
                 }
          }            

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值