32: Simple use of Condition

This article has participated in the "Newcomer Creation Ceremony" event to start the road of gold creation together.


foreword

In 30: Simple use of ReentrantLock, the simple use of ReentrantLock is introduced. It can be simply considered that ReentrantLock is a more comprehensive synchronized API form. So how to implement ReentrantLock's blocking (synchronized wait) and wake-up (synchronized notify)? At this time, it is necessary to launch Condition introduced in JDK 1.5 like ReentrantLock. Compared with Object's wait() and notify() methods, Condition has more comprehensive features.

A Condition instance can be obtained through ReentrantLock.newCondition(). The Condition is bound to the ReentrantLock, and the thread holding the bound ReentrantLock can block and wake up through the Condition. Different from synchronized using lockObj's wait(), the notify() method has only one waiting queue, and a ReentrantLock can be bound with multiple Conditions, that is, multiple waiting queues can be set. A Condition represents a communication channel, but it should be noted that the wait command of each Condition can only be awakened by the same Condition. There is no cross-wakeup between different Conditions (see the code ConditionDemo).

Condition method introduction

  • await(): blocking waiting, equivalent to wait()
  • await(long time, TimeUnit unit): Block waiting for a specified time, and automatically wake up after the specified time to start competing for locks
  • awaitNanos(long nanosTimeout): nanosecond-level blocking waits for a specified time, and automatically wakes up after the specified time to start competing for locks
  • awaitUntil(Date deadline): Block waiting until a certain date, and automatically wake up to start competing locks when the deadline is reached
  • awaitUninterruptibly(): Uninterrupted waiting, in this waiting state, the thread will ignore its interrupt instruction
  • signal(): Wakes up a blocked thread, equivalent to notify().
  • signalAll(): wake up all blocked threads, equivalent to notifyAll()

Note that Condition also has wait() and notify() methods, because wait() and notify() belong to Object, and any class inherits Object. But wait() and notify() do not belong to the functions provided by Condition. They are only useful when Condition is used as a normal lock object using synchronized. So remember not to use await() to wait but want to use notify() to wake up, you can't wake up, they are not a set in themselves. Use await with signal, and wait with notify.

sample code

public class ConditionDemo {

    public static void main(String[] args) {
        final ReentrantLock lock = new ReentrantLock();
        final Condition c = lock.newCondition();

        /*---------------多个线程之间的相互唤醒------------------*/
        /**
        for (int i = 0; i < 5; i++) {
            final int j = i;
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        lock.lock();
                        System.out.println(j + "拿到锁");
                        System.out.println(j + "开始等待");
                        c.await(); 
                        System.out.println(j + "收到信号");
                        System.out.println(j + "发出信号");
                        c.signal();
                    } catch (Exception e) {
                        System.out.println("2error");   
                        e.printStackTrace();   
                    } finally {
                        lock.unlock(); // 一定记得要解锁!!!
                    }
                }
            });
            t.start();
        }
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        lock.lock();
        System.out.println("主线程拿到锁");
        System.out.println("主线程发出信号");
        // 唤醒是signal不是notify,notify是使用关键字synchronized时的唤醒方法!!!
        //  使用notify会抛java.lang.IllegalMonitorStateException异常
        c.signal();   // 唤醒,默认优先唤醒先等待的线程
//        c.signalAll();    // 唤醒全部         
        System.out.println("主线程释放锁");
        lock.unlock();
        **/
        /*---------------多个线程之间的相互唤醒------------------*/
        
        /*---------------几种等待机制------------------*/
        /**
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lock.lock();
                    System.out.println("1拿到锁");
                    System.out.println("1等待开始");
//                    c.await();    // 等待
//                    c.await(1, TimeUnit.SECONDS); //等待1s, 1s后解除等待开始竞争资源
//                    c.awaitNanos(1000L);// 等待1000纳秒  
//                    c.awaitUntil(new Date(new Date().getTime() + 1000)); // 等待到某一日期
                    c.awaitUninterruptibly();   // 无中断的等待,在这个等待状态下,此线程会无视对他的中断指令
                    System.out.println("1被唤醒");
                } catch (Exception e) {
                    System.out.println("1error");
                    e.printStackTrace();
                } finally {
                    lock.unlock(); 
                }
            }
        });

        t1.start();
        try {
            Thread.sleep(1000);  // 等待1s确保t1进入等待状态,避免主线程先抢到资源执行完毕后t1得到资源才开始等待
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t1.interrupt();  // awaitUninterruptibly时这个语句被无视,其它等待下会抛异常java.lang.InterruptedException
        lock.lock();
        System.out.println("主线程拿到锁");
        System.out.println("主线程发出信号");
        c.signal(); // 唤醒
        lock.unlock(); // 释放锁
        **/
        /*---------------几种等待机制------------------*/
      
      

      /*-----线程3用以验证睡眠是否释放锁及验证Condition之间无法相互唤醒-----*/
      /**
        Thread t3 = new Thread(new Runnable() {
          @Override
          public void run() {
              try {
                  lock.lock();
                  System.out.println("3拿到锁");
                  System.out.println("3开始等待");
                  c.await();
                  System.out.println("3收到信号");
              } catch (Exception e) {
                  System.out.println("3error");   
                  e.printStackTrace();   
              } finally {
                  lock.unlock();
              }
          }
      });
      */
      /*-----线程3用以验证睡眠是否释放锁及验证Condition之间无法相互唤醒-----*/


      /*--------线程持有锁并睡眠时间是不会释放资源(锁)的------------*/
        /**
      lock.lock();
      t3.start();
      System.out.println("主线程拿到锁");
      System.out.println("主线程开始睡眠");
        try {
            Thread.sleep(1000); // 线程持有锁并睡眠时间是不会释放资源(锁)的
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       System.out.println("主线程睡眠结束");
       lock.unlock();
       */
       /*--------线程持有锁并睡眠时间是不会释放资源(锁)的------------*/
       
       /*---------------不同Condition之间无法相互唤醒------------------*/
        /**
      final Condition c2 = lock.newCondition();
      try {
          Thread.sleep(1000);
      } catch (InterruptedException e) {
          e.printStackTrace();
      }
        lock.lock();
//        c.signalAll();
        c2.signalAll(); // c2并不能唤醒c的等待线程
        lock.unlock();
        */
        /*---------------不同Condition之间无法相互唤醒------------------*/
    }

}
复制代码

The journey of development and growth [continuously updated...]
Associated navigation: 30: Simple use of ReentrantLock - Nuggets (juejin.cn)
welcome to pay attention...

Guess you like

Origin juejin.im/post/7080130193364369421