Поместите один поток в спящий режим, пока условие не будет разрешено в другом потоке
вот два куска кода, которые выполняют (то, что я думаю) то же самое.
Я в основном пытаюсь узнать, как использовать многопоточность в Java 1.5, чтобы уйти от потока.спать дольше.) Первый пример использует ReentrantLock и второй пример использует CountDownLatch за. Суть того, что я пытаюсь сделать, заключается в том, чтобы усыпить один поток, пока условие не будет разрешено в другом потоке.
ReentrantLock обеспечивает блокировку логического значения, которое я использую, чтобы решить, чтобы разбудить другой поток или нет, а затем я использую условие с await/signal для сна другого потока. Насколько я могу судить, единственная причина, по которой мне нужно будет использовать блокировки, - это если более одного потока требуется доступ на запись к boolean.
CountDownLatch, похоже, предоставляет ту же функциональность, что и ReentrantLock, но без (ненужного?) защелкивания. Тем не менее, похоже, что я вроде как угоняю его предполагаемое использование, инициализируя его только с одним необходимым обратным отсчетом. Я думаю он должен использоваться, когда несколько потоков будут работать над одной задачей, а не когда несколько потоков ждут одной задачи.
Итак, вопросы:
Я использую замки для "правильной вещи" в коде ReentrantLock? Если я пишу только логическое значение в одном потоке, необходимы ли блокировки? Пока я сбрасываю boolean перед пробуждением любых других потоков, я не могу вызвать проблему, не так ли?
есть класс, подобный 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;
}
}
3 ответов
любой подход примерно эквивалентен, за исключением того, что a CountDownLatch может быть выпущен только один раз. После этого все await () вызовы возвращают мгновенно. Так CyclicBarrier может быть более подходящим, если вы работаете со службой, которая может идти вниз и вверх.
Если ваше состояние действительно является одноразовой сделкой, то FutureTask было бы более уместно. Вы могли бы позвонить get () который будет ждать служба станет доступной, а затем вы сможете использовать службу, как только get() вернется.
вы упоминаете, что CountDownLatch позволяет ждать без использования блокировок. Тем не менее, как CountDownLatch и ReentrantLock реализуются с помощью AbstractQueuedSynchronizer. Под капотом они обеспечивают идентичную семантику синхронизации и видимости.
подход переменной блокировки/условия лучше для этой задачи, на мой взгляд. Вот пример, похожий на ваш: 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). Однако проблема с не использованием блокировок заключается в том, что в зависимости от того, как долго ваша служба не работает для вас вращение на while (isServiceDown ()). Используя условие wait, вы говорите ОС, чтобы спать ваш поток до ложного пробуждения (о котором говорилось в Java docs for Condition) или до тех пор, пока условие не будет сигнализировано в другом потоке.
ПОЛНЫЙ ПОВТОРНЫЙ ВХОД ЗАБЛОКИРОВАН ПРИМЕР АСИНХРОННОЙ ЗАДАЧИ:
СО СХЕМОЙ ПОТОКА КОДА: