Java スレッドが連携するにはどのような方法がありますか?

王林
リリース: 2023-05-17 20:34:15
転載
1493 人が閲覧しました

なぜスレッドは連携する必要があるのですか?

スレッドは特定の作業を完了するために互いに連携します。たとえば、あるスレッドがオブジェクトの値を変更し、別のスレッドがその変更を感知して、対応する処理を実行します。操作。プロセス全体が 1 つのスレッドで開始され、最後の実行は別のスレッドで行われます。このモデルにより、生産者と消費者が分離され、「何を」「どのように」の分離が実現します。簡単な方法は、コンシューマ スレッドを継続的にループさせて変数が期待を満たしているかどうかをチェックし、満たされていない条件を while ループに設定し、条件が満たされた場合に while ループを終了することで、コンシューマの作業を完了することです。この種のスレッド間のコラボレーションには 2 つの問題があります。

(1) 適時性を確保することが困難です。

(2) オーバーヘッドの削減が難しい。 1 ミリ秒スリープするなど、スリープ時間を短縮すると、コンシューマは状態の変化をより迅速に検出できますが、より多くのプロセッサ リソースが消費され、不必要な無駄が発生する可能性があります。

はじめに

Java でのスレッド コラボレーションの最も一般的な 2 つの方法: Object.wait()、Object.notify() の使用、および Condition の使用

メソッド 1

Object の wait、notify、notifyAll メソッドは次のように定義されています

  • publicfinalnativevoidnotify();publicfinalnativevoidnotifyAll();publicfinalnativevoidwait (長いタイムアウト) InterruptedException をスローします。

  • ##wait()、notify()、およびnotifyAll() メソッドはローカル メソッドおよび最終メソッドであり、オーバーライドできません

  • #オブジェクトの wait() メソッドを呼び出して現在のスレッドをブロックします。現在のスレッドはこのオブジェクトのモニター (つまりロック) を所有している必要があります
  • オブジェクトの通知を呼び出す() メソッドは、このオブジェクトのモニターを待機しているスレッドをウェイクアップできます。このオブジェクトのモニターを待機しているスレッドが複数ある場合、そのうちの 1 つのスレッドのみをウェイクアップできます
  • Call notificationAll( ) メソッドは、このオブジェクトのモニターを待機しているすべてのスレッドを起動できます
  • ##これら 3 つのメソッドが Object クラスで宣言されている理由は、各オブジェクトがモニター (つまり、ロック)
  • オブジェクトの wait() メソッドを呼び出すには、現在のスレッドがこのオブジェクトのモニター (つまり、ロック) を所有している必要があるため、wait() メソッドを呼び出します。メソッドは同期ブロックまたは同期メソッドで実行する必要があります
  • public class Test {
        public static Object object = new Object();
        public static void main(String[] args) {
            Thread1 thread1 = new Thread1();
            Thread2 thread2 = new Thread2();
            thread1.start();
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread2.start();
        }
        static class Thread1 extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    try {
                        object.wait();
                    } catch (InterruptedException e) {
                    }
                    System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
                }
            }
        }
        static class Thread2 extends Thread{
            @Override
            public void run() {
                synchronized (object) {
                    object.notify();
                    System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
                }
                System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
            }
        }
    }
    ログイン後にコピー
実行結果

スレッド Thread-1 は object.notify と呼ばれました()

スレッド Thread-1 がロックを解放しました
スレッド Thread-0 がロックを取得しました



メソッド 2

条件は Java でのみ出現します1.5では、従来のObjectを置き換えるために使用されます Condition1のwait()とnotify()はスレッド間の連携を実現します Objectのwait()とnotify()を使用するのに比べて、await()とnotify()を使用する方が安全かつ効率的です
  • Condition はインターフェイスであり、基本的なメソッドは await() メソッドと signal() メソッドです
  • Condition は、Lock インターフェイスに依存して、Condition の基本コードを生成します。それは lock.newCondition()です。
  • Condition の await() メソッドと signal() メソッドの呼び出しは、ロック保護内にある必要があります。つまり、lock.lock() と lock の間になければなりません。これは、unlocks の間でのみ使用できます
  • Example
  • public class Test {
        private int queueSize = 10;
        private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
        private Lock lock = new ReentrantLock();
        private Condition notFull = lock.newCondition();
        private Condition notEmpty = lock.newCondition();
        public static void main(String[] args)  {
            Test test = new Test();
            Producer producer = test.new Producer();
            Consumer consumer = test.new Consumer();
            producer.start();
            consumer.start();
        }
        class Consumer extends Thread{
            @Override
            public void run() {
                consume();
            }
            private void consume() {
                while(true){
                    lock.lock();
                    try {
                        while(queue.size() == 0){
                            try {
                                System.out.println("队列空,等待数据");
                                notEmpty.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        queue.poll();                //每次移走队首元素
                        notFull.signal();
                        System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                    } finally{
                        lock.unlock();
                    }
                }
            }
        }
        class Producer extends Thread{
            @Override
            public void run() {
                produce();
            }
            private void produce() {
                while(true){
                    lock.lock();
                    try {
                        while(queue.size() == queueSize){
                            try {
                                System.out.println("队列满,等待有空余空间");
                                notFull.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        queue.offer(1);        //每次插入一个元素
                        notEmpty.signal();
                        System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                    } finally{
                        lock.unlock();
                    }
                }
            }
        }
    }
    ログイン後にコピー

以上がJava スレッドが連携するにはどのような方法がありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート