なぜそれが2つのスレッドが私のコードで1錠にアクセスしているように見えるのでしょうか?

ジェームズ:

私は、Javaのマルチスレッドを学ぶしようとしているが、これは(単純leetcodeの同時実行の問題ですhttps://leetcode.com/problems/print-foobar-alternately/)。私は、次のコードを思い付いたが、それが動作する理由を私は理解していません。問題は、一つのスレッドの呼び出しfooと一つのスレッドのコールバーを言うと、それは「foobarに」n回を印刷する必要があります。

public class Foobar {
    int n;
    boolean hasFoo;
    Lock lock;
    Condition cond;
    public Foobar(int n) {
        this.n = n;
        hasFoo = false;
        lock = new ReentrantLock();
        cond = lock.newCondition();
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            lock.lock();
            while (hasFoo) {
                cond.await();
            }
            printFoo.run();
            hasFoo = true;
            cond.signalAll();
            lock.unlock();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        for (int i = 0; i < n; i++) {
            lock.lock();
            while (!hasFoo) {
                cond.await();
            }
            printBar.run();
            hasFoo = false;
            cond.signalAll();
            lock.unlock();
        }
    }
}

それは動作しますが、私は理由を理解していません。「バー」スレッドが最初に実行され、ロックを取得した場合私の理解から、それは待たなければならないと「foo」というスレッドがブロックされますlock.lock();ラインが、それらの両方がロックされた一部を入力するからそれが点灯します。私はJavaでロック誤解どこ私を啓発してください。ここで私はこれらの2つのメソッドを呼び出す方法です。

        Foobar f = new Foobar(10);
        Runnable rf = () -> {
            try {
                f.foo(() -> System.out.println("foo"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
        Runnable rp = () -> {
            try {
                f.bar(() -> System.out.println("bar"));
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
        Thread t1 = new Thread(rf, "foo-thread");
        Thread t2 = new Thread(rp, "bar-thread");
        t1.start();
        t2.start();
アンドリューTobilko:

「バー」スレッドが最初に実行され、ロックを取得した場合、それは待つ必要があります...

何のために待って?「バー」スレッドがロックを取得し、その最初のものである、待つことは何もありません。このスレッドはすぐにある、次の文に進みますcond.await();ロックが解除される場所1を、そしてスレッドがスリープ状態になります。

一方、「foo」というスレッドがロック取得することができる2、そのメッセージを印刷し、そのジョブは、その後、ロック解除れ、行われていることを他人に知らせる3睡眠「バー」。

...「foo」というスレッドがでブロックされます lock.lock();

丁度。

それは、彼らの両方がロックされた一部を入力判明します。

一つは、入力された番号、別のは、入るのを待っています。それは、単純なロックだ- 1つのスレッドのみ(それはの高度なバージョンのようなものだ時にそれを取得することができsynchronized声明)。


1この条件に関連付けられているロックは原子的に解放され、現在のスレッドは、スレッドスケジューリングを目的と嘘休眠のために無効になります

https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/concurrent/locks/Condition.html#await()

2「バー」はそれをやった後にそれがロック背の低い人を取得しようとしたので、それがブロックされたことを覚えておいてください。

ロックが利用できない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、ロックが取得されるまで嘘が休止します。

https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/concurrent/locks/Lock.html#lock()

3全てへのシグナリングによって、のいずれかの4つの方法覚醒他の人に。

  1. いくつかの他のスレッドが起動されますsignalAll()。このための方法をCondition

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html#await()

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=233283&siteId=1