Table of contents
Open Table of contents
Locks in Java (Part 3)
Using Condition
Using Condition with Lock is equivalent to using wait/notify with synchronized.
Methods in Condition
- void await() = wait
- void await(long nanos) with a timeout = wait(long timeout)
- void signal = notify wake one waiting thread
- void signalAll() = notifyAll wake all waiting threads
Important Points
As with wait and notify, you must acquire the lock before calling await, signal, or signalAll.
Implementing Wait and Notify
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import lombok.SneakyThrows;
import org.junit.Test;
/**
* Combine Lock and Condition to implement waiting and notification. Remember to release the lock. All waiting and notification operations must take place between lock and unlock.
*
* Lock lock = new ReentrantLock();
* Condition condition = lock.newCondition();
* lock.lock;/lock.tryLock();/lock.tryLock(long nanos)
* try{
* condition.await();/condition.await(long nanos);/condition.signal();/condition.signalAll();
* } finally {
* lock.unlock();
* }
*
* @author jacksparrow414
* @date 2020/10/21
*/
public final class ThreadLockConditionTest {
// Reentrant lock; nonfair by default
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
static boolean flag = true;
@Test
@SneakyThrows
public void assertLockCondition() {
Thread threadN = new Thread(new ThreadLockConditionTest.threadN(), "threadN");
Thread threadM = new Thread(new ThreadLockConditionTest.threadM(), "threadM");
threadN.start();
TimeUnit.SECONDS.sleep(1);
threadM.start();
TimeUnit.SECONDS.sleep(10);
}
static class threadN implements Runnable {
@Override
public void run() {
// Do not put lock acquisition inside the try block. If an exception occurs while acquiring a custom lock,
//the exception could also cause the lock to be released incorrectly.
lock.lock();
while (flag) {
System.out.println(Thread.currentThread().getName() + " flag is true wait");
try {
condition.await();
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
// Remember to release the reentrant lock manually
lock.unlock();
}
System.out.println(Thread.currentThread().getName() + "falg is false running");
}
}
}
static class threadM implements Runnable {
@Override
public void run() {
lock.lock();
System.out.println(Thread.currentThread().getName() + " acquire lock");
flag = false;
// Wake all waiting threads
try {
TimeUnit.SECONDS.sleep(3);
condition.signalAll();
} catch (InterruptedException exception) {
exception.printStackTrace();
}finally {
lock.unlock();
}
// The operation that wakes waiting threads must be inside the synchronized section, or an error will occur
// condition.signalAll();
lock.lock();
System.out.println(Thread.currentThread().getName() + " acquire again");
condition.signalAll();
lock.unlock();
}
}
}