Поместите один поток в режим сна, пока условие не будет разрешено в другом потоке
Вот две части кода, которые выполняют (что я думаю) одно и то же.
В основном я пытаюсь научиться использовать Java 1.5 concurrency, чтобы уйти от Thread.sleep(long). В первом примере используется ReentrantLock, а во втором примере используется CountDownLatch. Суть того, что я пытаюсь сделать, - поставить один поток в режим сна, пока условие не будет разрешено в другом потоке.
ReentrantLock обеспечивает блокировку логического, который я использую, чтобы решить, следует ли разбудить другой поток или нет, а затем я использую условие с await/signal, чтобы спать в другом потоке. Насколько я могу судить, единственной причиной, по которой мне нужно будет использовать блокировки, является то, что для более одного потока требуется доступ на запись к логическому.
Функция CountDownLatch, как представляется, обеспечивает те же функции, что и ReentrantLock, но без блокировок (ненужных?). Тем не менее, похоже, что я как бы захватил его предполагаемое использование, инициализируя его только одним обратным отсчетом. Я думаю, что он должен использоваться, когда несколько потоков будут работать над одной задачей, а не когда несколько потоков ждут по одной задаче.
Итак, вопросы:
-
Использую ли я блокировки для "правильной вещи" в коде ReentrantLock? Если я пишу только в буле в одном потоке, нужны ли блокировки? Пока я reset логический, прежде чем просыпать любые другие потоки, я не могу вызвать проблему, могу ли я?
-
Есть ли класс, похожий на CountDownLatch, который я могу использовать, чтобы избежать блокировок (предполагая, что я должен избегать их в этом экземпляре), что более естественно подходит для этой задачи?
-
Есть ли другие способы улучшить этот код, о котором я должен знать?
ПРИМЕР ПЕРВЫЙ:
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;
}
}
ПРИМЕР ДВА:
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;
}
}
Ответы
Ответ 1
Любой подход примерно эквивалентен, за исключением того, что CountDownLatch может быть выпущен только один раз. После этого все await() вызовы возвращаются мгновенно. Таким образом, CyclicBarrier может быть более подходящим, если вы работаете с сервисом, который может опускаться и подниматься.
Если ваше условие действительно является сделкой с одним выстрелом, более подходящим будет FutureTask. Вы можете вызвать get(), который будет ждать, пока служба станет доступной, а затем вы сможете использовать эту услугу, как только get() вернется.
Вы отмечаете, что CountDownLatch позволяет ждать без использования Locks. Тем не менее, как CountDownLatch, так и ReentrantLock реализованы с использованием AbstractQueuedSynchronizer. Под капотом они обеспечивают идентичную семантику синхронизации и видимости.
Ответ 2
Подход к блокировке/условию лучше для этой задачи, на мой взгляд. Здесь приведен пример, похожий на ваш: http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/Condition.html
В ответ на защиту булева. Вы можете использовать volatile (http://www.ibm.com/developerworks/java/library/j-jtp06197.html). Однако проблема с не использованием Locks заключается в том, что в зависимости от того, как долго ваш сервис будет работать, вы будете вращаться во время (isServiceDown()). Используя условие wait, вы указываете ОС, чтобы спать с вашим потоком до тех пор, пока не появится ложный сигнал (обсуждаемый в java-документах для условия) или пока условие не будет сигнализировано в другом потоке.
Ответ 3
С СХЕМА ПОТОКА КОДА:
![enter image description here]()