多线程

1. 概述

1.1 多线程的重要性

多线程是现代编程的核心技术之一,能够充分利用多核CPU,提高程序执行效率,实现并发处理。

本文内容

  • 线程基础:线程概念和生命周期
  • 线程创建:创建线程的多种方式
  • 线程同步:synchronized、Lock等同步机制
  • 线程通信:wait/notify、Condition等通信机制
  • 线程池:线程池的使用和原理
  • 并发工具:CountDownLatch、CyclicBarrier等工具
  • 线程安全:线程安全问题和解决方案
  • 死锁问题:死锁的产生和避免

1.2 本文内容结构

本文将从以下几个方面深入探讨多线程:

  1. 线程基础:线程概念和生命周期
  2. 线程创建:创建线程的方式
  3. 线程同步:同步机制和锁
  4. 线程通信:线程间通信方式
  5. 线程池:线程池的使用和原理
  6. 并发工具:并发工具类的使用
  7. 线程安全:线程安全问题解决
  8. 死锁问题:死锁的产生和避免

2. 线程基础

2.1 线程概念

2.1.1 进程和线程

进程:操作系统资源分配的基本单位,每个进程有独立的内存空间。

线程:CPU调度的基本单位,同一进程内的线程共享内存空间。

进程 vs 线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
进程:
┌─────────────────────────┐
│ 进程1(独立内存空间) │
│ ┌──────┐ ┌──────┐ │
│ │线程1 │ │线程2 │ │
│ └──────┘ └──────┘ │
└─────────────────────────┘

线程:
┌─────────────────────────┐
│ 共享内存空间 │
│ ┌──────┐ ┌──────┐ │
│ │线程1 │ │线程2 │ │
│ └──────┘ └──────┘ │
└─────────────────────────┘

多线程优势

  1. 提高CPU利用率:充分利用多核CPU
  2. 提高响应速度:避免阻塞,提高用户体验
  3. 资源利用:共享内存,节省资源

2.2 线程生命周期

2.2.1 线程状态

线程状态

  1. NEW(新建):线程创建,未启动
  2. RUNNABLE(可运行):线程可执行
  3. BLOCKED(阻塞):等待获取锁
  4. WAITING(等待):无限期等待
  5. TIMED_WAITING(超时等待):有限期等待
  6. TERMINATED(终止):线程执行完毕

线程状态转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ThreadStateExample {

public void threadStates() {
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000); // TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}
});

System.out.println(thread.getState()); // NEW

thread.start();
System.out.println(thread.getState()); // RUNNABLE

try {
Thread.sleep(100);
System.out.println(thread.getState()); // TIMED_WAITING
} catch (InterruptedException e) {
e.printStackTrace();
}

try {
thread.join();
System.out.println(thread.getState()); // TERMINATED
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

3. 线程创建

3.1 继承Thread类

3.1.1 创建线程方式1

继承Thread类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ThreadExample1 extends Thread {

@Override
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
System.out.println("Count: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
ThreadExample1 thread = new ThreadExample1();
thread.start(); // 启动线程
}
}

注意

  • 调用start()方法启动线程,会创建新线程执行run()方法
  • 直接调用run()方法不会创建新线程,只是普通方法调用

3.2 实现Runnable接口

3.2.1 创建线程方式2

实现Runnable接口(推荐):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ThreadExample2 implements Runnable {

@Override
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
System.out.println("Count: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) {
ThreadExample2 runnable = new ThreadExample2();
Thread thread = new Thread(runnable);
thread.start();

// 使用Lambda表达式
Thread thread2 = new Thread(() -> {
System.out.println("Lambda thread running");
});
thread2.start();
}
}

优势

  • 避免单继承限制
  • 代码更灵活
  • 适合资源共享

3.3 实现Callable接口

3.3.1 创建线程方式3

实现Callable接口(有返回值):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.util.concurrent.*;

public class ThreadExample3 implements Callable<String> {

@Override
public String call() throws Exception {
System.out.println("Callable thread running");
Thread.sleep(2000);
return "Callable result: " + Thread.currentThread().getName();
}

public static void main(String[] args) throws Exception {
Callable<String> callable = new ThreadExample3();
FutureTask<String> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();

// 获取返回值(会阻塞直到任务完成)
String result = futureTask.get();
System.out.println("Result: " + result);

// 使用线程池
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);
String result2 = future.get();
System.out.println("Result2: " + result2);
executor.shutdown();
}
}

Callable vs Runnable

  • Callable有返回值,Runnable无返回值
  • Callable可以抛出异常,Runnable不能
  • Callable配合Future使用

3.4 线程池创建

3.4.1 创建线程方式4

使用线程池(推荐):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.concurrent.*;

public class ThreadPoolExample {

public static void main(String[] args) {
// 使用线程池创建线程
ExecutorService executor = Executors.newFixedThreadPool(5);

for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running in " +
Thread.currentThread().getName());
});
}

executor.shutdown();
}
}

4. 线程同步

4.1 synchronized关键字

4.1.1 synchronized用法

synchronized:Java内置的同步机制,保证同一时刻只有一个线程执行同步代码。

synchronized用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class SynchronizedExample {

private int count = 0;
private final Object lock = new Object();

// 方式1:synchronized方法
public synchronized void increment1() {
count++;
}

// 方式2:synchronized静态方法
public static synchronized void increment2() {
// 类锁
}

// 方式3:synchronized代码块(对象锁)
public void increment3() {
synchronized (this) {
count++;
}
}

// 方式4:synchronized代码块(指定锁对象)
public void increment4() {
synchronized (lock) {
count++;
}
}
}

synchronized原理

1
2
3
4
5
6
7
8
9
10
11
12
public class SynchronizedPrinciple {

public synchronized void method1() {
// 同步方法
}

public void method2() {
synchronized (this) {
// 同步代码块
}
}
}

字节码层面

  • synchronized方法:方法标志位ACC_SYNCHRONIZED
  • synchronized代码块:monitorentermonitorexit指令

4.2 Lock接口

4.2.1 ReentrantLock

ReentrantLock:可重入锁,功能比synchronized更强大。

ReentrantLock使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.concurrent.locks.ReentrantLock;

public class LockExample {

private int count = 0;
private final ReentrantLock lock = new ReentrantLock();

public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 释放锁(必须在finally中)
}
}

// 尝试获取锁
public void tryLockExample() {
if (lock.tryLock()) { // 尝试获取锁,不阻塞
try {
count++;
} finally {
lock.unlock();
}
} else {
System.out.println("Failed to acquire lock");
}
}

// 可中断锁
public void interruptibleLock() throws InterruptedException {
lock.lockInterruptibly(); // 可中断的获取锁
try {
count++;
} finally {
lock.unlock();
}
}
}

ReentrantLock vs synchronized

特性 synchronized ReentrantLock
自动释放 否(需手动)
可中断
公平锁 是(可配置)
条件变量
性能 Java 6后优化,性能相当 性能相当

4.3 ReadWriteLock

4.3.1 读写锁

ReadWriteLock:读写分离锁,提高并发性能。

读写锁使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {

private int data = 0;
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

// 读操作(共享锁)
public int read() {
readWriteLock.readLock().lock();
try {
return data;
} finally {
readWriteLock.readLock().unlock();
}
}

// 写操作(独占锁)
public void write(int value) {
readWriteLock.writeLock().lock();
try {
data = value;
} finally {
readWriteLock.writeLock().unlock();
}
}
}

读写锁特点

  • 多个读线程可以同时获取读锁
  • 写线程独占写锁,与其他线程互斥
  • 适合读多写少的场景

4.4 volatile关键字

4.4.1 volatile的作用

volatile:保证变量的可见性和有序性,不保证原子性。

volatile使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class VolatileExample {

// volatile保证可见性
private volatile boolean flag = false;

public void writer() {
flag = true; // 写操作
}

public void reader() {
while (!flag) {
// 读操作,能及时看到flag的变化
}
System.out.println("Flag is true");
}

// volatile不保证原子性
private volatile int count = 0;

public void increment() {
count++; // 不是原子操作,volatile不能保证
}

// 正确方式:使用synchronized或AtomicInteger
private final AtomicInteger atomicCount = new AtomicInteger(0);

public void atomicIncrement() {
atomicCount.incrementAndGet(); // 原子操作
}
}

volatile原理

  • 禁止指令重排序
  • 强制刷新到主内存
  • 保证可见性

5. 线程通信

5.1 wait/notify

5.1.1 等待通知机制

wait/notify:Object类的方法,实现线程间通信。

wait/notify使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class WaitNotifyExample {

private final Object lock = new Object();
private boolean condition = false;

// 等待线程
public void waitThread() throws InterruptedException {
synchronized (lock) {
while (!condition) {
System.out.println("Waiting...");
lock.wait(); // 释放锁,等待通知
}
System.out.println("Condition is true, continue...");
}
}

// 通知线程
public void notifyThread() {
synchronized (lock) {
condition = true;
lock.notify(); // 通知等待的线程
// lock.notifyAll(); // 通知所有等待的线程
}
}
}

wait/notify注意事项

  1. 必须在synchronized代码块中使用
  2. 调用wait()会释放锁
  3. notify()随机唤醒一个线程
  4. notifyAll()唤醒所有等待的线程

5.2 Condition

5.2.1 条件变量

Condition:Lock接口的条件变量,功能类似wait/notify。

Condition使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {

private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean flag = false;

public void await() throws InterruptedException {
lock.lock();
try {
while (!flag) {
condition.await(); // 等待
}
System.out.println("Condition is true");
} finally {
lock.unlock();
}
}

public void signal() {
lock.lock();
try {
flag = true;
condition.signal(); // 通知
// condition.signalAll(); // 通知所有
} finally {
lock.unlock();
}
}
}

Condition优势

  • 可以创建多个Condition
  • 更灵活的线程通信
  • 支持公平锁

5.3 生产者消费者

5.3.1 经典案例

生产者消费者模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumerExample {

private final Queue<Integer> queue = new LinkedList<>();
private final int CAPACITY = 10;
private final Object lock = new Object();

// 生产者
public void produce(int value) throws InterruptedException {
synchronized (lock) {
while (queue.size() == CAPACITY) {
System.out.println("Queue is full, waiting...");
lock.wait(); // 队列满,等待
}
queue.offer(value);
System.out.println("Produced: " + value);
lock.notifyAll(); // 通知消费者
}
}

// 消费者
public int consume() throws InterruptedException {
synchronized (lock) {
while (queue.isEmpty()) {
System.out.println("Queue is empty, waiting...");
lock.wait(); // 队列空,等待
}
int value = queue.poll();
System.out.println("Consumed: " + value);
lock.notifyAll(); // 通知生产者
return value;
}
}
}

6. 线程池

6.1 线程池原理

6.1.1 为什么使用线程池

线程池优势

  1. 降低资源消耗:复用线程,减少创建和销毁开销
  2. 提高响应速度:任务到达时,线程已存在
  3. 提高线程管理:统一管理线程,控制并发数

线程池核心参数

1
2
3
4
5
6
7
8
9
10
11
public class ThreadPoolCoreParams {

// ThreadPoolExecutor构造函数参数
// 1. corePoolSize:核心线程数
// 2. maximumPoolSize:最大线程数
// 3. keepAliveTime:空闲线程存活时间
// 4. unit:时间单位
// 5. workQueue:工作队列
// 6. threadFactory:线程工厂
// 7. handler:拒绝策略
}

6.2 线程池创建

6.2.1 Executors工具类

Executors工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.util.concurrent.*;

public class ExecutorsExample {

public void executorsExample() {
// 1. 固定线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(10);

// 2. 单线程池
ExecutorService singlePool = Executors.newSingleThreadExecutor();

// 3. 缓存线程池
ExecutorService cachedPool = Executors.newCachedThreadPool();

// 4. 定时线程池
ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(5);

// 提交任务
fixedPool.submit(() -> {
System.out.println("Task running");
});

// 关闭线程池
fixedPool.shutdown();
}
}

注意Executors创建的线程池可能有问题,建议使用ThreadPoolExecutor

6.3 自定义线程池

6.3.1 ThreadPoolExecutor

自定义线程池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.concurrent.*;

public class CustomThreadPool {

public void customThreadPool() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(100), // 工作队列
new ThreadFactory() { // 线程工厂
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("CustomThread-" + thread.getId());
thread.setDaemon(false);
return thread;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

// 提交任务
for (int i = 0; i < 20; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running");
});
}

// 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
}

6.4 拒绝策略

6.4.1 四种拒绝策略

拒绝策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RejectionPolicy {

// 1. AbortPolicy:直接抛出异常(默认)
RejectedExecutionHandler abortPolicy = new ThreadPoolExecutor.AbortPolicy();

// 2. CallerRunsPolicy:调用者运行策略
RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();

// 3. DiscardPolicy:直接丢弃任务
RejectedExecutionHandler discardPolicy = new ThreadPoolExecutor.DiscardPolicy();

// 4. DiscardOldestPolicy:丢弃最老的任务
RejectedExecutionHandler discardOldestPolicy = new ThreadPoolExecutor.DiscardOldestPolicy();
}

7. 并发工具类

7.1 CountDownLatch

7.1.1 倒计时门闩

CountDownLatch:等待多个线程完成。

CountDownLatch使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {

public void countDownLatchExample() throws InterruptedException {
int threadCount = 5;
CountDownLatch latch = new CountDownLatch(threadCount);

for (int i = 0; i < threadCount; i++) {
final int taskId = i;
new Thread(() -> {
try {
System.out.println("Task " + taskId + " running");
Thread.sleep(1000);
latch.countDown(); // 计数减1
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}

latch.await(); // 等待所有任务完成
System.out.println("All tasks completed");
}
}

7.2 CyclicBarrier

7.2.1 循环栅栏

CyclicBarrier:多个线程互相等待。

CyclicBarrier使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {

public void cyclicBarrierExample() {
int threadCount = 3;
CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
System.out.println("All threads reached barrier");
});

for (int i = 0; i < threadCount; i++) {
final int threadId = i;
new Thread(() -> {
try {
System.out.println("Thread " + threadId + " waiting at barrier");
barrier.await(); // 等待其他线程
System.out.println("Thread " + threadId + " passed barrier");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}

7.3 Semaphore

7.3.1 信号量

Semaphore:控制并发数量。

Semaphore使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.concurrent.Semaphore;

public class SemaphoreExample {

public void semaphoreExample() {
int permits = 3; // 允许3个线程同时执行
Semaphore semaphore = new Semaphore(permits);

for (int i = 0; i < 10; i++) {
final int taskId = i;
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println("Task " + taskId + " running");
Thread.sleep(1000);
semaphore.release(); // 释放许可
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}

7.4 CompletableFuture

7.4.1 异步编程

CompletableFuture:异步编程工具。

CompletableFuture使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {

public void completableFutureExample() {
// 异步执行
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "Hello";
}).thenApply(s -> s + " World")
.thenApply(String::toUpperCase);

// 获取结果
future.thenAccept(result -> {
System.out.println("Result: " + result);
});

// 组合多个Future
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");

CompletableFuture<String> combined = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);
combined.thenAccept(System.out::println);
}
}

8. 线程安全

8.1 线程安全问题

8.1.1 问题示例

线程安全问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ThreadSafetyProblem {

private int count = 0;

// 线程不安全:多线程同时执行会导致count值不正确
public void increment() {
count++; // 不是原子操作
}

// 解决方案1:使用synchronized
public synchronized void incrementSync() {
count++;
}

// 解决方案2:使用AtomicInteger
private final AtomicInteger atomicCount = new AtomicInteger(0);

public void incrementAtomic() {
atomicCount.incrementAndGet();
}
}

8.2 原子类

8.2.1 Atomic类

原子类:保证操作的原子性。

原子类使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.concurrent.atomic.*;

public class AtomicExample {

// AtomicInteger
private final AtomicInteger atomicInt = new AtomicInteger(0);

public void atomicIntExample() {
atomicInt.incrementAndGet(); // 原子递增
atomicInt.getAndIncrement(); // 先获取再递增
atomicInt.compareAndSet(0, 10); // CAS操作
}

// AtomicLong
private final AtomicLong atomicLong = new AtomicLong(0);

// AtomicReference
private final AtomicReference<String> atomicRef = new AtomicReference<>("initial");

public void atomicRefExample() {
atomicRef.compareAndSet("initial", "updated");
}

// AtomicIntegerArray
private final AtomicIntegerArray atomicArray = new AtomicIntegerArray(10);

public void atomicArrayExample() {
atomicArray.set(0, 10);
atomicArray.compareAndSet(0, 10, 20);
}
}

8.3 线程安全集合

8.3.1 并发集合

线程安全集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.concurrent.*;

public class ConcurrentCollectionExample {

// ConcurrentHashMap
private final ConcurrentHashMap<String, String> concurrentMap = new ConcurrentHashMap<>();

// CopyOnWriteArrayList
private final CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();

// BlockingQueue
private final BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<>();

public void blockingQueueExample() throws InterruptedException {
// 生产者
blockingQueue.put("item"); // 阻塞直到有空间

// 消费者
String item = blockingQueue.take(); // 阻塞直到有元素
}
}

9. 死锁问题

9.1 死锁产生

9.1.1 死锁条件

死锁产生的四个必要条件

  1. 互斥条件:资源不能被多个线程共享
  2. 请求与保持:线程持有资源并请求新资源
  3. 不可剥夺:资源不能被强制释放
  4. 循环等待:形成循环等待链

死锁示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class DeadlockExample {

private final Object lock1 = new Object();
private final Object lock2 = new Object();

public void method1() {
synchronized (lock1) {
System.out.println("Method1 acquired lock1");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Method1 acquired lock2");
}
}
}

public void method2() {
synchronized (lock2) {
System.out.println("Method2 acquired lock2");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Method2 acquired lock1");
}
}
}

// 可能产生死锁
public void deadlockTest() {
new Thread(this::method1).start();
new Thread(this::method2).start();
}
}

9.2 死锁避免

9.2.1 避免死锁的方法

避免死锁的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class DeadlockAvoidance {

private final Object lock1 = new Object();
private final Object lock2 = new Object();

// 方法1:按顺序获取锁
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// 业务逻辑
}
}
}

public void method2() {
synchronized (lock1) { // 与method1相同的顺序
synchronized (lock2) {
// 业务逻辑
}
}
}

// 方法2:使用tryLock
public void method3() {
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();

while (true) {
if (lock1.tryLock()) {
try {
if (lock2.tryLock()) {
try {
// 业务逻辑
return;
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
// 获取锁失败,稍后重试
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

9.3 死锁检测

9.3.1 检测死锁

检测死锁

1
2
3
4
5
6
7
8
9
10
11
12
# 使用jstack检测死锁
jstack <pid>

# 输出示例
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007f8b1c0001e8 (object 0x000000076ab622a0, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007f8b1c0002b8 (object 0x000000076ab622b0, a java.lang.Object),
which is held by "Thread-1"

10. 实战案例

10.1 线程安全的单例

10.1.1 双重检查锁定

线程安全的单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ThreadSafeSingleton {

private static volatile ThreadSafeSingleton instance;

private ThreadSafeSingleton() {}

public static ThreadSafeSingleton getInstance() {
if (instance == null) {
synchronized (ThreadSafeSingleton.class) {
if (instance == null) {
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
}

10.2 线程池实战

10.2.1 自定义线程池

自定义线程池实战

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class ThreadPoolPractice {

public void customThreadPool() {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new ThreadFactory() {
private int count = 0;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setName("Worker-" + (++count));
return thread;
}
},
new ThreadPoolExecutor.CallerRunsPolicy()
);

// 提交任务
for (int i = 0; i < 100; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " running in " +
Thread.currentThread().getName());
});
}

executor.shutdown();
}
}

11. 总结

11.1 核心要点

  1. 线程创建:继承Thread、实现Runnable/Callable、使用线程池
  2. 线程同步:synchronized、Lock、volatile
  3. 线程通信:wait/notify、Condition
  4. 线程池:合理使用线程池,避免频繁创建线程
  5. 线程安全:使用原子类、并发集合
  6. 死锁避免:按顺序获取锁、使用tryLock

11.2 关键理解

  1. synchronized和Lock:功能类似,Lock更灵活
  2. volatile:保证可见性,不保证原子性
  3. 线程池:复用线程,提高性能
  4. 并发工具:简化并发编程

11.3 最佳实践

  1. 优先使用线程池:避免手动创建线程
  2. 合理使用锁:减少锁的粒度,避免死锁
  3. 使用并发集合:线程安全的集合类
  4. 避免共享可变状态:使用不可变对象

相关文章