zoukankan      html  css  js  c++  java
  • java多线程-Condition

    ConditionObject 监视器方法(waitnotifynotifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。

    先看一个关于Condition使用的简单实例:

     1 public class ConditionTest {
     2     public static void main(String[] args) {
     3         final Lock lock = new ReentrantLock();
     4         final Condition condition = lock.newCondition();
     5         
     6         Thread thread1 = new Thread(new Runnable() {
     7             @Override
     8             public void run() {
     9                 try {
    10                     lock.lock();
    11                     System.out.println("我需要等一个信号"+this);
    12                     condition.await();
    13                     System.out.println("我拿到一个信号"+this);
    14                 } catch (Exception e) {
    15                     // TODO: handle exception
    16                 } finally{
    17                     lock.unlock();
    18                 }
    19                 
    20                 
    21             }
    22         }, "thread1");
    23         thread1.start();
    24         Thread thread2 = new Thread(new Runnable() {
    25             @Override
    26             public void run() {
    27                 try {
    28                     lock.lock();
    29                     System.out.println("我拿到了锁");
    30                     Thread.sleep(500);
    31                     System.out.println("我发出一个信号");
    32                     condition.signal();
    33                 } catch (Exception e) {
    34                     // TODO: handle exception
    35                 } finally{
    36                     lock.unlock();
    37                 }
    38                 
    39                 
    40             }
    41         }, "thread2");
    42         thread2.start();
    43     }
    44 }

    运行结果:

    1 我需要等一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c9
    2 我拿到了锁
    3 我发出一个信号
    4 我拿到一个信号com.luchao.traditionalthread.ConditionTest$1@10bc3c9
    View Code

    可以看到,Condition的执行方式,是当在线程1中调用await方法后,线程1将释放锁,并且将自己沉睡,等待唤醒,线程2获取到锁后,开始做事,完毕后,调用Condition的signal方法,唤醒线程1,线程1恢复执行。

    以上说明Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。

    Condition与传统线程通信有些类似,它的使用更广,可以将多个线程进行通信,以完成更加复杂的通信。

    用Condition替换传统线程通信,在前面的传统有一个子线程和主线程交替运行50次的实例,使用Condition也可以完成。

    代码如下:

     1 public class ConditionCommuniction {
     2     public static void main(String[] args) {
     3         final Business business = new Business();
     4         new Thread(new Runnable() {
     5             @Override
     6             public void run() {
     7                 for (int i = 0; i < 50; i++) {
     8                     business.sub(i);
     9                 }
    10             }
    11         }).start();
    12         for (int i = 0; i < 50; i++) {
    13             business.main(i);
    14         }
    15     }
    16     
    17     
    18     static class Business{
    19         private Lock lock = new ReentrantLock();
    20         private boolean isMain = true;
    21         private Condition condition = lock.newCondition();
    22         public void main(int i){
    23             lock.lock();
    24             try {
    25                 while(!isMain){
    26                     condition.await();
    27                 }
    28                 for (int j = 0; j < 100; j++) {
    29                     System.out.println("main is looping  :" + j +" in " + i);
    30                 }
    31                 isMain = false;
    32                 condition.signal();
    33             } catch (Exception e) {
    34                 // TODO: handle exception
    35             } finally{
    36                 lock.unlock();
    37             }
    38         }
    39         public void sub(int i){
    40             lock.lock();
    41             try {
    42                 while(isMain){
    43                     condition.await();
    44                 }
    45                 for (int j = 0; j < 10; j++) {
    46                     System.out.println("sub is looping  :" + j +" in " + i);
    47                 }
    48                 isMain = true;
    49                 condition.signal();
    50             } catch (Exception e) {
    51                 // TODO: handle exception
    52             } finally{
    53                 lock.unlock();
    54             }
    55         }
    56     }
    57 }

      在Condition中,用await()替换wait(),用signal()替换notify(),用signalAll()替换notifyAll(),传统线程的通信方式,Condition都可以实现,这里注意,Condition是被绑定到Lock上的,要创建一个Lock的Condition必须用newCondition()方法。

       这样看来,Condition和传统的线程通信没什么区别,Condition的强大之处在于它可以为多个线程间建立不同的Condition,下面引入API中的一段代码,加以说明。

     1 class BoundedBuffer {  
     2    final Lock lock = new ReentrantLock();//锁对象  
     3    final Condition notFull  = lock.newCondition();//写线程条件   
     4    final Condition notEmpty = lock.newCondition();//读线程条件   
     5   
     6    final Object[] items = new Object[100];//缓存队列  
     7    int putptr/*写索引*/, takeptr/*读索引*/, count/*队列中存在的数据个数*/;  
     8   
     9    public void put(Object x) throws InterruptedException {  
    10      lock.lock();  
    11      try {  
    12        while (count == items.length)//如果队列满了   
    13          notFull.await();//阻塞写线程  
    14        items[putptr] = x;//赋值   
    15        if (++putptr == items.length) putptr = 0;//如果写索引写到队列的最后一个位置了,那么置为0  
    16        ++count;//个数++  
    17        notEmpty.signal();//唤醒读线程  
    18      } finally {  
    19        lock.unlock();  
    20      }  
    21    }  
    22   
    23    public Object take() throws InterruptedException {  
    24      lock.lock();  
    25      try {  
    26        while (count == 0)//如果队列为空  
    27          notEmpty.await();//阻塞读线程  
    28        Object x = items[takeptr];//取值   
    29        if (++takeptr == items.length) takeptr = 0;//如果读索引读到队列的最后一个位置了,那么置为0  
    30        --count;//个数--  
    31        notFull.signal();//唤醒写线程  
    32        return x;  
    33      } finally {  
    34        lock.unlock();  
    35      }  
    36    }   
    37  }  

      这就是多个Condition的强大之处,假设缓存队列中已经存满,那么阻塞的肯定是写线程,唤醒的肯定是读线程,相反,阻塞的肯定是读线程,唤醒的肯定是写线程,那么假设只有一个Condition会有什么效果呢,缓存队列中已经存满,这个Lock不知道唤醒的是读线程还是写线程了,如果唤醒的是读线程,皆大欢喜,如果唤醒的是写线程,那么线程刚被唤醒,又被阻塞了,这时又去唤醒,这样就浪费了很多时间。

      将上面主线程和子线程交替运行的程序进行扩展,三个线程交替运行,代码如下:

     1 public class ThreeConditionCommunication {
     2     public static void main(String[] args) {
     3         final Business business = new Business();
     4         new Thread(new Runnable() {
     5             
     6             @Override
     7             public void run() {
     8                 for (int i = 0; i < 50; i++) {
     9                     business.sub1(i);
    10                 }
    11             }
    12         }).start();
    13         new Thread(new Runnable() {
    14             
    15             @Override
    16             public void run() {
    17                 for (int i = 0; i < 50; i++) {
    18                     business.sub2(i);
    19                 }
    20             }
    21         }).start();
    22         for (int i = 0; i < 50; i++) {
    23             business.main(i);
    24         }
    25     }
    26     static class Business{
    27         Lock lock = new ReentrantLock();
    28         Condition main = lock.newCondition();
    29         Condition sub1 = lock.newCondition();
    30         Condition sub2 = lock.newCondition();
    31         int runNum = 1;
    32         
    33         public void main(int i){
    34             lock.lock();
    35             try {
    36                 while(runNum!=1){
    37                     main.await();//主线程等待
    38                 }
    39                 for (int j = 0; j < 100; j++) {
    40                     System.out.println("main is looping of "+j+" in "+i);
    41                 }
    42                 runNum = 2;
    43                 sub1.signal();//唤醒子线程1
    44             } catch (Exception e) {
    45                 // TODO: handle exception
    46             } finally{
    47                 lock.unlock();
    48             }
    49         }
    50         public void sub1(int i){
    51             lock.lock();
    52             try {
    53                 while(runNum!=2){
    54                     sub1.await();//子线程1等待
    55                 }
    56                 for (int j = 0; j < 10; j++) {
    57                     System.out.println("sub1 is looping of "+j+" in "+i);
    58                 }
    59                 runNum = 3;
    60                 sub2.signal();//唤醒子线程2
    61             } catch (Exception e) {
    62                 // TODO: handle exception
    63             } finally{
    64                 lock.unlock();
    65             }
    66         }
    67         public void sub2(int i){
    68             lock.lock();
    69             try {
    70                 while(runNum!=3){
    71                     sub2.await();//子线程2等待
    72                 }
    73                 for (int j = 0; j < 20; j++) {
    74                     System.out.println("sub2 is looping of "+j+" in "+i);
    75                 }
    76                 runNum = 1;
    77                 main.signal();//唤醒主线程
    78             } catch (Exception e) {
    79                 // TODO: handle exception
    80             } finally{
    81                 lock.unlock();
    82             }
    83         }
    84     }
    85 }

    由此可见,Condition在多线程通信的强大作用,可以大大提高程序效率。

  • 相关阅读:
    Linux用root强制踢掉已登录用户;用fail2ban阻止ssh暴力破解root密码
    JDBC开发
    JSP指令与动作元素
    Jsp——状态管理
    JavaBeans
    JSP——九大内置对象
    Jsp基础语法
    WEB-INF目录结构
    JavaWeb简介
    UML——初识
  • 原文地址:https://www.cnblogs.com/lcngu/p/5208465.html
Copyright © 2011-2022 走看看