これは、(私が思うに) 同じことを達成する 2 つのコードの塊です。
私は基本的に、Java 1.5 の同時実行性を使用して Thread.sleep(long) から逃れる方法を学ぼうとしています。最初の例では ReentrantLock を使用し、2 番目の例では CountDownLatch を使用しています。私がやろうとしていることの要点は、別のスレッドで状態が解決されるまで、1 つのスレッドをスリープ状態にすることです。
ReentrantLock は、他のスレッドをウェイクアップするかどうかを決定するために使用しているブール値にロックを提供し、次に条件を await/signal と共に使用して他のスレッドをスリープさせます。私が知る限り、ロックを使用する必要がある唯一の理由は、複数のスレッドがブール値への書き込みアクセスを必要とする場合です。
CountDownLatch は ReentrantLock と同じ機能を提供しているようですが、(不要な?) ロックはありません。ただし、必要なカウントダウンが1つだけで初期化することで、意図した用途を乗っ取っているような気がします。複数のスレッドが1つのタスクで待機している場合ではなく、複数のスレッドが同じタスクで動作する場合に使用することになっていると思います。
だから、質問:
ReentrantLock コードで「正しいこと」のためにロックを使用していますか? 1 つのスレッドでブール値にのみ書き込みを行う場合、ロックは必要ですか? 他のスレッドを起動する前にブール値をリセットする限り、問題は発生しませんよね?
このタスクにより自然に適した、ロックを回避するために使用できる CountDownLatch に似たクラスはありますか (このインスタンスではロックを回避する必要があると仮定します)。
このコードを改善するために知っておくべき他の方法はありますか?
例 1:
import java.util.concurrent.locks.*;
public class ReentrantLockExample extends Thread {
//boolean - Is the service down?
boolean serviceDown;
// I am using this lock to synchronize access to sDown
Lock serviceLock;
// and this condition to sleep any threads waiting on the service.
Condition serviceCondition;
public static void main(String[] args) {
Lock l = new ReentrantLock();
Condition c = l.newCondition();
ReentrantLockExample rle = new ReentrantLockExample(l, c);
//Imagine this thread figures out the service is down
l.lock();
try {
rle.serviceDown = true;
} finally {
l.unlock();
}
int waitTime = (int) (Math.random() * 5000);
System.out.println("From main: wait time is " + waitTime);
rle.start();
try {
//Symbolizes some random time that the service takes to come back up.
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Imagine this thread figures out that the service is back up.
l.lock();
try {
rle.serviceDown = false;
c.signal();
} finally {
l.unlock();
}
}
//Constructor
public ReentrantLockExample(Lock l, Condition c) {
this.serviceLock = l;
this.serviceCondition = c;
}
/*
* Should wait for this imaginary service to come back online.
*/
public void run() {
System.out.println("Thread: start awaiting");
serviceLock.lock();
try {
while (isServiceDown())
{
serviceCondition.await();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
serviceLock.unlock();
}
System.out.println("Thread: done awaiting");
}
private boolean isServiceDown() {
return serviceDown;
}
}
例 2:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;
public class CountDownLatchExample extends Thread {
//boolean - Is the service down?
boolean serviceDown;
// I am using this latch to wait on the service.
CountDownLatch serviceLatch;
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(1);
CountDownLatchExample cdle = new CountDownLatchExample(cdl);
//Service goes down.
cdle.serviceDown = true;
int waitTime = (int) (Math.random() * 5000);
System.out.println("From main: wait time is " + waitTime);
cdle.start();
try {
//Symbolizes some random time that the service takes to come back up.
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Service comes back up.
cdle.serviceDown = false;
cdl.countDown();
}
//Constructor
public CountDownLatchExample(CountDownLatch cdl) {
this.serviceLatch = cdl;
}
/*
* Should wait for this imaginary service to come back online.
*/
public void run() {
System.out.println("Thread: start awaiting");
try {
while (isServiceDown()) {
serviceLatch.await();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Thread: done awaiting");
}
private boolean isServiceDown() {
return serviceDown;
}
}