2

だから私が達成したいのは、2つのスレッドが順番にタスクを実行することです。当初、私が持っていた質問は 1 つだけでした。

  1. ロックを使用せずにタスクを順番に実行する 2 つのスレッドを実現するにはどうすればよいですか? ロックが必要ない理由は、2 つのスレッドがアクセスしようとしている共通のリソースがない場合にロックを使用するのは愚かだと感じているからです。

だから私はコードの小さな例を作るつもりでしたが、ロックを使ってもそれを機能させることができないことに気付きました。私の 2 番目の質問は次のとおりです。コードを期待どおりに動作させるにはどうすればよいですか? 私の見方では、うまくいくはずですが、それは私だけです:)

  1. Thread1 はメッセージを出力します
  2. スレッド 1 は、スレッド 2 がメッセージを出力できることを通知します
  3. Thread2 はメッセージを出力します
  4. Thread2 は、Thread1 が最初からやり直すことができることを通知します

public class App {

    Lock lock = new ReentrantLock();
    Condition cond1 = lock.newCondition();
    Condition cond2 = lock.newCondition();

    public App() {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        lock.lock();
                        System.out.println("Thread 1");
                        cond2.signalAll();
                        cond1.await();
                        lock.unlock();
                    }
                } catch (InterruptedException e) {
                }
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        lock.lock();
                        cond2.await();
                        System.out.println("           Thread 2");
                        cond1.signalAll();
                        lock.unlock();
                    }
                } catch (InterruptedException e) {
                }
            }
        });
        thread2.start();
    }

    public static void main(String[] args) {
        new App();
    }

}
4

2 に答える 2

2

(1)await()通常はループで使用されます。そうしないと、バグの兆候です。

while( some condition not met )
    cond.await();

(2)ブロックunlock()内にある必要がありますfinally

(3)signal()現在待機中のスレッドのみを通知します。待っているスレッドがない場合、シグナルは失われます。

    lock.lock();
    cond.signal(); // lost
    cond.await();  // won't wake up

synchronized(4)このような単純な場合に古き良きを使用することは何も悪いことではありません。実際には、より「高度な」ものを使用する前に、まずそれをよく理解してください。

(5) 解決策:

    Lock lock = new ReentrantLock();
    Condition cond = lock.newCondition();
    int turn=1; // 1 or 2


    // thread1

            lock.lock();
            try
            {
                while (true)
                {
                    while(turn!=1)
                        cond.await();
                    System.out.println("Thread 1");
                    turn=2;
                    cond.signal();
                }
            }
            finally
            {
                lock.unlock();
            }

    // thread2
    // switch `1` and `2`

(6) スレッドのリング、それぞれが次のスレッドを起こす

    int N = 9;
    Thread[] ring = new Thread[N];
    for(int i=0; i<N; i++)
    {
        final int ii = i+1;
        ring[i] = new Thread(()->
        {
            while(true)
            {
                LockSupport.park();   // suspend this thread
                System.out.printf("%"+ii+"d%n", ii);
                LockSupport.unpark(ring[ii%N]);  // wake up next thread
                // bug: spurious wakeup not handled 
            }
        });
    }

    for(Thread thread : ring)
        thread.start();

    LockSupport.unpark(ring[0]);  // wake up 1st thread
于 2015-05-30T03:02:12.100 に答える