目录
2. Object类中的wait和notify方法实现线程等待和唤醒
3. Condition接口中的await和signal方法实现线程等待和唤醒
4. await、signal与wait、notify总结:
1. LockSupport
LockSupport
的主要功能如下:
-
线程阻塞:
LockSupport.park()
方法可以阻塞当前线程,直到被其他线程调用LockSupport.unpark(Thread thread)
方法或者被中断。 -
线程唤醒:
LockSupport.unpark(Thread thread)
方法可以唤醒指定被阻塞的线程。
LockSupport
与传统的线程通信方法(如 Object.wait()
和 Object.notify()
)相比,具有以下特点:
- 无需持有锁:
park
和unpark
方法不需要线程持有任何锁。 - 不可重入性:
park
方法被设计为不可重入的,即在一个线程已经调用park
后,再次调用park
将会导致线程永久阻塞。 - 更低的延迟:
LockSupport
提供的阻塞和唤醒操作通常具有更低的延迟。
以下是一些 LockSupport
的常用方法:
void park()
:阻塞当前线程,直到被unpark
或线程被中断。void park(Object blocker)
:同park()
,但允许记录导致线程阻塞的阻塞对象,主要用于诊断问题。void parkNanos(long nanos)
:阻塞当前线程,最长不超过指定的纳秒数。void parkUntil(long deadline)
:阻塞当前线程,直到某个时间 deadline。void unpark(Thread thread)
:唤醒处于阻塞状态的指定线程。
2. Object类中的wait和notify方法实现线程等待和唤醒
public class WaitNotifyExample {
public static void main(String[] args) {
final Object lock = new Object();
// 创建一个生产者线程
Thread producer = new Thread(() -> {
synchronized (lock) {
System.out.println("Producer thread is running...");
try {
// 模拟生产过程
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 生产完成,通知消费者
lock.notify();
System.out.println("Producer thread has notified the consumer thread.");
try {
// 为了演示,生产者线程在这里等待,让消费者线程执行
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer thread has been notified and is resuming...");
}
});
// 创建一个消费者线程
Thread consumer = new Thread(() -> {
synchronized (lock) {
try {
// 消费者线程等待生产者线程的通知
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer thread has been notified and is now consuming the product.");
// 模拟消费过程
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 消费完成后,通知生产者
lock.notify();
System.out.println("Consumer thread has finished consuming and notified the producer thread.");
}
});
// 启动线程
consumer.start();
producer.start();
}
}
3. Condition接口中的await和signal方法实现线程等待和唤醒
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AwaitSignalExample {
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) {
// 创建一个生产者线程
Thread producerThread = new Thread(() -> {
lock.lock();
try {
System.out.println("Producer thread is running...");
// 模拟生产过程
Thread.sleep(2000);
System.out.println("Producer thread has finished production and is signaling the consumer thread.");
condition.signal(); // 通知消费者线程
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
// 再次尝试获取锁并等待消费者线程的通知
lock.lock();
try {
System.out.println("Producer thread is waiting for consumer thread to finish consumption.");
condition.await(); // 等待消费者线程的通知
System.out.println("Producer thread has been signaled and is resuming...");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
// 创建一个消费者线程
Thread consumerThread = new Thread(() -> {
lock.lock();
try {
System.out.println("Consumer thread is waiting for producer thread to produce.");
condition.await(); // 等待生产者线程的通知
System.out.println("Consumer thread has been signaled and is consuming the product.");
// 模拟消费过程
Thread.sleep(1000);
System.out.println("Consumer thread has finished consumption and is signaling the producer thread.");
condition.signal(); // 通知生产者线程
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
});
// 启动线程
consumerThread.start();
producerThread.start();
}
}
4. await、signal与wait、notify总结:
- 线程先要获取并持有锁,必须在锁块(synchronized或lock)中
- 必须先等待后唤醒,线程才能被唤醒
5. park和unpark
LockSupport用于创建锁和其他同步类的基本线程阻塞原语
LockSupport类使用一种名为Permit(许可)的概念来阻塞和唤醒线程的功能,每个线程都有一个许可(permit)
与Semaphore不同的是,许可累加上限是1
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 is running...");
// 当前线程将在这里阻塞,直到被unpark
LockSupport.park();
System.out.println("Thread has been unparked and is running again.");
});
// 启动线程
thread.start();
// 主线程暂停一段时间,确保工作线程有机会阻塞
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 解除工作线程的阻塞状态
LockSupport.unpark(thread);
}
}
注意:先执行unpark后执行park会使park如同虚设,因为已经获取到了许可了,park就会直接放行