Java 并发编程
Java 并发编程
Java 并发编程的核心问题是:多个线程同时访问共享资源时,如何保证数据正确性。关键概念包括锁、内存可见性、线程协作。
并发编程知识结构:
wait() 和 sleep() 的区别
| 方法 | 所属 | 是否释放锁 | 唤醒方式 |
|---|---|---|---|
wait() | Object | 是,释放对象锁 | notify() / notifyAll() |
sleep() | Thread | 否,不释放锁 | 超时 / 中断 |
// wait 需要在 synchronized 块中调用
synchronized (mon) {
mon.wait(); // 释放锁,进入等待状态
}
// sleep 不释放锁
synchronized(LOCK) {
Thread.sleep(1000); // LOCK 仍然被持有
}注意
伪唤醒防护 wait() 可能发生伪唤醒(spurious wakeup),必须用循环检查条件:
while (!condition) { mon.wait(); }ThreadLocal
为每个线程提供独立的对象实例,避免线程安全问题。
private static final ThreadLocal<SimpleDateFormat> formatter =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd HHmm"));内存泄漏风险
线程池中线程是复用的,不调用 remove() 清理会导致引用一直存在。使用完必须 threadLocal.remove()。
ThreadLocal 工作原理:
Runnable vs Thread
实现 Runnable 优于继承 Thread——灵活且不占用继承位。Runnable 是任务抽象,Thread 是线程载体。
// 推荐
new Thread(new MyTask()).start();阻塞队列
BlockingQueue 是 JUC 包提供的线程安全队列,支持阻塞式存取,常用于生产者-消费者模式。
| 状态 | 行为 |
|---|---|
| 队列为空 | 消费者阻塞,等待非空 |
| 队列已满 | 生产者阻塞,等待非满 |
生产者-消费者模式:
| 实现 | 类型 | 说明 |
|---|---|---|
| ArrayBlockingQueue | 有界 | 基于数组,需指定容量 |
| LinkedBlockingQueue | 可选有界 | 基于链表,默认无界 |
| DelayQueue | 无界 | 延迟获取元素 |
| SynchronousQueue | 不存储 | 直接传递,一对一交接 |
| 方法 | 队列满/空时 | 返回值 |
|---|---|---|
put(e) | 阻塞等待 | void |
take() | 阻塞等待 | E |
offer(e) | 返回 false | boolean |
poll() | 返回 null | E |
DelayQueue 示例:
public class DelayedTask implements Delayed {
private long executeTime;
private Runnable task;
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return Long.compare(this.executeTime, ((DelayedTask) o).executeTime);
}
}