Here are two chunks of code that accomplish (what I think is) the same thing.
I basically am trying to learn how to use Java 1.5's concurrency to get away from Thread.sleep(long). The first example uses ReentrantLock, and the second example uses CountDownLatch. The jist of what I am trying to do is put one thread to sleep until a condition is resolved in another thread.
The ReentrantLock provides a lock on the boolean I'm using to decide whether to wake the other thread or not, and then I use the Condition with await/signal to sleep the other thread. As far as I can tell, the only reason I would need to use locks is if more than one thread required write access to the boolean.
The CountDownLatch seems to provide the same functionality as the ReentrantLock but without the (unnecessary?) locks. However, it feels like I am kind of hijacking its intended use by initializing it with only one countdown necessary. I think it's supposed to be used when multiple threads are going to be working on the same task, not when multiple threads are waiting on one task.
So, questions:
Am I using locks for "the right thing" in the ReentrantLock code? If I am only writing to the boolean in one thread, are the locks necessary? As long as I reset the boolean before waking up any other threads I can't cause a problem, can I?
Is there a class similar to CountDownLatch I can use to avoid locks (assuming I should be avoiding them in this instance) that is more naturally suited to this task?
Are there any other ways to improve this code I should be aware of?
EXAMPLE ONE:
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;
}
}
EXAMPLE TWO:
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;
}
}