32:条件の簡単な使用

この記事は、「新人クリエーションセレモニー」イベントに参加し、一緒にゴールドクリエーションの道を歩み始めました。


序文

30 ReentrantLockの簡単な使用法では、ReentrantLockの簡単な使用法が紹介されています。ReentrantLockは、より包括的な同期APIフォームであると簡単に考えることができます。では、ReentrantLockのブロッキング(同期待機)とウェイクアップ(同期通知)を実装するにはどうすればよいですか?このとき、ReentrantLockのようにJDK 1.5で導入された条件を起動する必要があります。オブジェクトのwait()、notify()メソッド、Conditionと比較してより包括的な機能があります。

Conditionインスタンスは、ReentrantLock.newCondition()を介して取得できます。ConditionはReentrantLockにバインドされ、バインドされたReentrantLockを保持しているスレッドは、Conditionを介してブロックおよびウェイクアップできます。lockObjのwait()を使用して同期するのとは異なり、notify()メソッドには待機キューが1つだけあり、ReentrantLockを複数の条件にバインドできます。つまり、複数の待機キューを設定できます。条件は通信チャネルを表しますが、各条件の待機コマンドは同じ条件によってのみ起動できることに注意してください。異なる条件間のクロスウェイクアップはありません(コードConditionDemoを参照)。

コンディションメソッド紹介

  • await():待機をブロックします。wait()と同等です。
  • await(long time、TimeUnit unit):指定された時間待機をブロックし、指定された時間後に自動的にウェイクアップしてロックの競合を開始します
  • awaitNanos(long nanosTimeout):ナノ秒レベルのブロッキングは指定された時間待機し、指定された時間後に自動的にウェイクアップしてロックの競合を開始します
  • awaitUntil(Date deadline):特定の日付までの待機をブロックし、期限に達すると自動的にウェイクアップして競合するロックを開始します
  • awaitUninterruptibly():中断されない待機。この待機状態では、スレッドは割り込み命令を無視します。
  • signal():notify()と同等の、ブロックされたスレッドをウェイクアップします。
  • signalAll():notifyAll()と同等の、ブロックされたすべてのスレッドをウェイクアップします

wait()とnotify()はObjectに属し、どのクラスもObjectを継承するため、Conditionにはwait()メソッドとnotify()メソッドもあることに注意してください。ただし、wait()とnotify()は、Conditionによって提供される関数に属していません。これらは、Conditionが同期を使用して通常のロックオブジェクトとして使用される場合にのみ役立ちます。したがって、await()を使用して待機するのではなく、notify()を使用してウェイクアップすることを忘れないでください。ウェイクアップすることはできません。これらは、それ自体が設定されていません。シグナルで待機し、通知で待機します。

サンプルコード

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之间无法相互唤醒------------------*/
    }

}
复制代码

開発と成長の旅[継続的に更新...]
関連するナビゲーション:30:ReentrantLockの簡単な使用-ナゲッツ(juejin.cn)
は注意を払うことを歓迎します...

おすすめ

転載: juejin.im/post/7080130193364369421