本文目录导读:

- 基础案例:线程的挂起与恢复
- 等待超时机制
- 生产者-消费者模式实现
- 可中断的等待(响应中断)
- 银行账户转账安全示例(实际应用场景)
- 高级案例:实现一个简单的AQS(AbstractQueuedSynchronizer)
- 注意事项与最佳实践
- 关键知识点总结
我将为你提供几个Java LockSupport 的实用案例,从基础到高级,帮助你理解线程阻塞与唤醒机制。
基础案例:线程的挂起与恢复
import java.util.concurrent.locks.LockSupport;
public class BasicLockSupportDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 开始执行");
// 阻塞当前线程,直到被唤醒
LockSupport.park();
System.out.println(Thread.currentThread().getName() + " 被唤醒,继续执行");
}, "Worker-Thread");
thread.start();
Thread.sleep(2000); // 主线程休眠2秒
System.out.println("主线程准备唤醒工作线程");
// 唤醒指定线程
LockSupport.unpark(thread);
}
}
等待超时机制
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.TimeUnit;
public class TimeoutLockSupportDemo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("开始等待数据...");
// 最多等待5秒
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
System.out.println("等待结束,继续执行");
});
thread.start();
// 主线程不主动唤醒,让工作线程超时自动继续
System.out.println("主线程不唤醒,让工作线程5秒后自动继续");
}
}
生产者-消费者模式实现
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.LockSupport;
public class ProducerConsumerWithLockSupport {
private static final Queue<Integer> QUEUE = new LinkedList<>();
private static final int MAX_SIZE = 5;
public static void main(String[] args) throws InterruptedException {
Thread consumerThread = new Thread(new Consumer(), "消费者");
Thread producerThread = new Thread(new Producer(), "生产者");
// 先启动消费者,确保它在等待中
consumerThread.start();
Thread.sleep(100);
producerThread.start();
}
static class Producer implements Runnable {
@Override
public void run() {
int count = 0;
while (count < 10) {
synchronized (QUEUE) {
if (QUEUE.size() < MAX_SIZE) {
QUEUE.add(count);
System.out.println("生产: " + count + ", 队列大小: " + QUEUE.size());
count++;
// 唤醒消费者
LockSupport.unpark(getConsumerThread());
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
synchronized (QUEUE) {
if (QUEUE.isEmpty()) {
System.out.println("队列为空,消费者等待...");
LockSupport.park(); // 阻塞消费者
System.out.println("消费者被唤醒");
} else {
Integer item = QUEUE.poll();
System.out.println("消费: " + item + ", 队列大小: " + QUEUE.size());
if (item != null && item == 9) {
break; // 消费完成
}
}
}
}
}
}
private static Thread getConsumerThread() {
// 这里简化处理,实际需要记录消费者线程引用
return Thread.currentThread();
}
}
可中断的等待(响应中断)
import java.util.concurrent.locks.LockSupport;
public class InterruptibleParkDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("线程开始执行");
// 检查中断状态
Thread.currentThread().interrupt();
// 如果线程被中断,park会立即返回
LockSupport.park();
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程被中断,park立即返回");
// 清除中断标志
Thread.interrupted();
}
System.out.println("继续执行");
});
thread.start();
thread.join();
System.out.println("主线程结束");
}
}
银行账户转账安全示例(实际应用场景)
import java.util.concurrent.locks.LockSupport;
public class BankTransferDemo {
static class BankAccount {
private String accountNo;
private double balance;
private Thread waitingThread; // 等待中的线程
public BankAccount(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
public synchronized void transfer(BankAccount to, double amount) {
System.out.println(Thread.currentThread().getName() +
" 尝试从 " + accountNo + " 转账 " + amount + " 到 " + to.accountNo);
if (balance < amount) {
System.out.println("余额不足,等待资金到账...");
// 保存当前线程,以便唤醒
this.waitingThread = Thread.currentThread();
// 释放锁并阻塞
LockSupport.park();
// 唤醒后重新检查
if (balance < amount) {
System.out.println("唤醒后仍余额不足,再次等待");
LockSupport.park();
}
}
this.balance -= amount;
to.balance += amount;
System.out.println("转账完成,当前余额: " + balance);
// 唤醒等待的线程
if (to.waitingThread != null) {
LockSupport.unpark(to.waitingThread);
}
}
public void deposit(double amount) {
this.balance += amount;
System.out.println("存款后余额: " + balance);
// 存款后唤醒等待的线程
if (waitingThread != null) {
LockSupport.unpark(waitingThread);
}
}
}
public static void main(String[] args) throws InterruptedException {
BankAccount accountA = new BankAccount("A", 100);
BankAccount accountB = new BankAccount("B", 500);
// 线程1:从A转账500到B(余额不足)
Thread t1 = new Thread(() -> {
accountA.transfer(accountB, 500);
}, "转账线程-1");
// 线程2:向A存款600
Thread t2 = new Thread(() -> {
try {
Thread.sleep(2000); // 延迟存款
accountA.deposit(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "存款线程-2");
t1.start();
Thread.sleep(100);
t2.start();
t1.join();
t2.join();
}
}
高级案例:实现一个简单的AQS(AbstractQueuedSynchronizer)
import java.util.concurrent.locks.LockSupport;
public class SimpleAQS {
private volatile int state = 0; // 0:未锁定,1:已锁定
private Thread owner; // 当前持有锁的线程
private Thread head; // 等待队列头
private Thread tail; // 等待队列尾
private ConcurrentLinkedQueue<Thread> waitQueue = new ConcurrentLinkedQueue<>();
public void lock() {
// 尝试获取锁
if (compareAndSetState(0, 1)) {
owner = Thread.currentThread();
return;
}
// 获取失败,加入等待队列
waitQueue.add(Thread.currentThread());
// 自旋等待
while (true) {
if (compareAndSetState(0, 1)) {
owner = Thread.currentThread();
waitQueue.remove(Thread.currentThread());
return;
}
// 挂起当前线程
LockSupport.park();
}
}
public void unlock() {
if (owner != Thread.currentThread()) {
throw new IllegalMonitorStateException();
}
// 释放锁
state = 0;
owner = null;
// 唤醒下一个等待线程
Thread nextThread = waitQueue.poll();
if (nextThread != null) {
LockSupport.unpark(nextThread);
}
}
private boolean compareAndSetState(int expect, int update) {
// 这里简化处理,实际应该用AtomicInteger的CAS
if (state == expect) {
state = update;
return true;
}
return false;
}
}
// 测试类
class LockSupportAQSExample {
public static void main(String[] args) throws InterruptedException {
SimpleAQS lock = new SimpleAQS();
Runnable task = () -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " 获得锁");
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " 释放锁");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
};
// 创建多个线程竞争锁
for (int i = 0; i < 3; i++) {
new Thread(task, "线程-" + i).start();
}
Thread.sleep(5000);
}
}
注意事项与最佳实践
import java.util.concurrent.locks.LockSupport;
public class LockSupportBestPractices {
public static void main(String[] args) throws InterruptedException {
// 1. park和unpark不需要按照特定顺序
demonstrateOrderIndependence();
// 2. 可以提前unpark
demonstrateEarlyUnpark();
// 3. 中断不会影响unpark
demonstrateInterruptBehavior();
}
private static void demonstrateOrderIndependence() throws InterruptedException {
System.out.println("=== 演示1:unpark可以先于park执行 ===");
Thread t1 = new Thread(() -> {
Thread.currentThread().interrupt();
LockSupport.park();
System.out.println("即使先interrupt,也能唤醒");
});
t1.start();
t1.join();
}
private static void demonstrateEarlyUnpark() {
System.out.println("=== 演示2:提前unpark ===");
Thread t2 = new Thread(() -> {
// park会立即返回,因为已经有许可
LockSupport.park();
System.out.println("线程2立即执行");
});
LockSupport.unpark(t2); // 提前给许可
t2.start();
}
private static void demonstrateInterruptBehavior() throws InterruptedException {
System.out.println("=== 演示3:中断行为 ===");
Thread t3 = new Thread(() -> {
Thread.currentThread().interrupt(); // 设置中断标志
LockSupport.park(); // 会立即返回
System.out.println("线程3响应中断");
});
t3.start();
t3.join();
}
}
关键知识点总结
| 方法 | 功能 | 特点 |
|---|---|---|
park() |
阻塞当前线程 | 不可超时 |
parkNanos(nanos) |
带超时的阻塞 | 自动唤醒 |
unpark(thread) |
唤醒指定线程 | 可提前给许可 |
parkUntil(deadline) |
指定时间点唤醒 | 绝对时间 |
注意事项:
- LockSupport是基于许可(permit)机制的,unpark会发送许可
- 与Object的wait/notify不同,LockSupport不需要synchronized
- 每个线程最多只有一个许可
- 不会抛出InterruptedException,但会响应中断标志
- 比wait/notify更灵活,可以精确唤醒指定线程
这些案例覆盖了LockSupport的主要使用场景,从基础到实际应用,在实际项目中,它是构建高级并发工具的基础。