【悲观锁】Synchronized和ReentrantLock的区别
【线程方法】多线程下 wait、notify、park、unpark 和 await、signal 的区别
【同步工具】CyclicBarrier和CountDownLatch的区别
1、所属类和包:
wait
和notify
属于Object
类,用于基本的对象监视器机制,而且它们必须在同步块或同步方法中使用。park
和unpark
属于sun.misc.Unsafe
类,提供了更底层的线程挂起和恢复操作。它们可以在任何地方使用,不需要在同步块中。await
和signal
属于java.util.concurrent.locks.Condition
接口,通常在ReentrantLock
的锁保护下使用。它们提供了更高级别的、更灵活的线程协作机制。
2、唤醒方式:
notify
只能唤醒等待在同一对象监视器上的一个线程。(调用notify
方法而没有任何等待的线程会引发IllegalMonitorStateException
异常)notifyAll
唤醒等待在同一对象监视器上的所有线程。(调用notifyAll
方法而没有任何等待的线程是不会引发异常的)unpark
可以指定唤醒哪个线程,因为需要传递线程对象作为参数。(当无park时执行unpark
不会异常,可以先执行unpark再执行park)signal
只能唤醒等待在相同Condition
对象上的一个线程(signal 唤醒等待在相同Condition
对象上的所有线程)。await
和signal
可以通过使用多个Condition
对象来实现更灵活的唤醒策略。
3、用法示例:
wait 和 notify:
synchronized (lock) {
while (conditionIsNotMet()) {
lock.wait();
}
// 执行满足条件时的操作
lock.notify();
}
park 和 unpark:
import java.util.concurrent.locks.LockSupport;
public class ParkUnparkExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " - Before park");
// 调用park,线程将被阻塞
LockSupport.park();
System.out.println(Thread.currentThread().getName() + " - After park");
});
// 启动线程
thread.start();
try {
Thread.sleep(2000); // 主线程等待一段时间
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - Before unpark");
// 调用unpark,唤醒指定线程
LockSupport.unpark(thread);
System.out.println(Thread.currentThread().getName() + " - After unpark");
}
}
await 和 signal:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AwaitSignalExample {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean conditionMet = false;
public void waitForCondition() throws InterruptedException {
lock.lock();
try {
while (!conditionMet) {
System.out.println(Thread.currentThread().getName() + " - Waiting for condition");
condition.await();
}
System.out.println(Thread.currentThread().getName() + " - Condition is met");
} finally {
lock.unlock();
}
}
public void signalCondition() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " - Signaling condition");
conditionMet = true;
condition.signal();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
AwaitSignalExample example = new AwaitSignalExample();
Thread waitingThread = new Thread(() -> {
try {
example.waitForCondition();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "WaitingThread");
Thread signalingThread = new Thread(example::signalCondition, "SignalingThread");
waitingThread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
signalingThread.start();
}
}