一、前言
本文将深入讲解Java多线程的核心内容,包括线程状态、多线程并发测试方法以及线程安全问题演示。通过大量的代码示例和运行截图,帮助大家彻底掌握Java多线程编程的基础。
二、线程生命周期详解
2.1 线程的六种状态
Java线程共有6种状态,定义在java.lang.Thread.State枚举中:
| 状态 | 说明 |
|---|---|
| NEW | 新建状态,线程被创建但未启动 |
| RUNNABLE | 可运行状态,等待CPU调度 |
| BLOCKED | 阻塞状态,等待获取监视器锁 |
| WAITING | 无限等待状态,需要被唤醒 |
| TIMED_WAITING | 限时等待状态,超时后自动唤醒 |
| TERMINATED | 终止状态,线程执行完毕 |
2.2 线程状态转换图

2.3 状态转换代码测试
java
/**
* 线程状态测试类
* 演示Java线程的六种状态及其转换
*/
public class ThreadStateTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 线程状态测试开始 ==========
");
// 1. 测试NEW状态
Thread newThread = new Thread(() -> {});
System.out.println("【NEW状态】新建线程但未启动: " + newThread.getState());
// 2. 测试RUNNABLE状态
Thread runnableThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
// 保持运行状态
}
});
runnableThread.start();
Thread.sleep(100);
System.out.println("【RUNNABLE状态】线程已启动正在运行: " + runnableThread.getState());
runnableThread.interrupt();
// 3. 测试BLOCKED状态
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
try { Thread.sleep(5000); } catch (InterruptedException e) {}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
System.out.println("t2获取到锁");
}
});
t1.start();
Thread.sleep(100); // 确保t1先获取锁
t2.start();
Thread.sleep(100);
System.out.println("【BLOCKED状态】t2等待获取锁: " + t2.getState());
// 4. 测试WAITING状态
Object waitObj = new Object();
Thread waitingThread = new Thread(() -> {
synchronized (waitObj) {
try {
waitObj.wait(); // 无限等待
} catch (InterruptedException e) {}
}
});
waitingThread.start();
Thread.sleep(100);
System.out.println("【WAITING状态】线程调用wait()等待: " + waitingThread.getState());
synchronized (waitObj) {
waitObj.notify(); // 唤醒线程
}
// 5. 测试TIMED_WAITING状态
Thread timedThread = new Thread(() -> {
try {
Thread.sleep(10000); // 限时等待10秒
} catch (InterruptedException e) {}
});
timedThread.start();
Thread.sleep(100);
System.out.println("【TIMED_WAITING状态】线程调用sleep(10000): " + timedThread.getState());
timedThread.interrupt();
// 6. 测试TERMINATED状态
Thread terminatedThread = new Thread(() -> {
System.out.println("线程执行中...");
});
terminatedThread.start();
terminatedThread.join(); // 等待线程执行完毕
System.out.println("【TERMINATED状态】线程执行完毕: " + terminatedThread.getState());
System.out.println("
========== 线程状态测试结束 ==========");
}
}
运行结果:
========== 线程状态测试开始 ==========
【NEW状态】新建线程但未启动: NEW
【RUNNABLE状态】线程已启动正在运行: RUNNABLE
【BLOCKED状态】t2等待获取锁: BLOCKED
【WAITING状态】线程调用wait()等待: WAITING
【TIMED_WAITING状态】线程调用sleep(10000): TIMED_WAITING
线程执行中...
【TERMINATED状态】线程执行完毕: TERMINATED
========== 线程状态测试结束 ==========
2.4 状态转换详解
NEW -> RUNNABLE :调用start()方法后,线程进入可运行状态,等待CPU调度。
RUNNABLE -> BLOCKED :线程尝试获取synchronized锁失败时,进入阻塞状态。
RUNNABLE -> WAITING :线程调用Object.wait()、Thread.join()或LockSupport.park()时进入无限等待状态。
RUNNABLE -> TIMED_WAITING :线程调用sleep(long)、wait(long)、join(long)时进入限时等待状态。
BLOCKED/WAITING/TIMED_WAITING -> RUNNABLE:获取锁成功、被唤醒或超时后,线程重新进入可运行状态。
RUNNABLE -> TERMINATED :线程的run()方法执行完毕或抛出未捕获异常时,进入终止状态。
三、多线程并发测试
3.1 基础多线程并发执行测试
java
/**
* 基础多线程并发测试
* 演示多个线程同时执行的效果
*/
public class BasicMultiThreadTest {
public static void main(String[] args) {
System.out.println("主线程开始执行...
");
// 创建3个线程并发执行
for (int i = 0; i < 3; i++) {
final int threadNum = i;
Thread thread = new Thread(() -> {
System.out.println("【" + Thread.currentThread().getName() + "】开始执行");
for (int j = 0; j < 5; j++) {
System.out.println("【" + Thread.currentThread().getName() + "】执行中... 计数: " + j);
try {
Thread.sleep(100); // 模拟任务执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("【" + Thread.currentThread().getName() + "】执行完毕
");
}, "Worker-" + i);
thread.start();
}
System.out.println("主线程继续执行其他任务...");
// 等待所有子线程执行完毕
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}
}
结果分析:
- 三个线程的执行顺序是不确定的,由CPU调度决定
- 主线程在启动子线程后继续执行,不会等待子线程
- 每个线程独立执行自己的任务,互不干扰
3.2 线程执行顺序测试
java
/**
* 线程执行顺序测试
* 演示线程启动顺序与执行顺序的关系
*/
public class ThreadOrderTest {
public static void main(String[] args) {
System.out.println("========== 线程执行顺序测试 ==========
");
// 创建5个线程
Thread[] threads = new Thread[5];
for (int i = 0; i < 5; i++) {
final int num = i;
threads[i] = new Thread(() -> {
System.out.println("线程 " + num + " 执行,名称: " + Thread.currentThread().getName());
}, "Thread-" + num);
}
// 按顺序启动线程
System.out.println("按顺序启动线程...");
for (Thread t : threads) {
t.start();
}
System.out.println("
注意:启动顺序 ≠ 执行顺序!");
}
}
运行结果:
========== 线程执行顺序测试 ==========
按顺序启动线程...
线程 1 执行,名称: Thread-1
线程 0 执行,名称: Thread-0
线程 3 执行,名称: Thread-3
线程 2 执行,名称: Thread-2
线程 4 执行,名称: Thread-4
注意:启动顺序 ≠ 执行顺序!
3.3 线程优先级测试
java
/**
* 线程优先级测试
* 演示线程优先级对执行的影响
*/
public class ThreadPriorityTest {
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 线程优先级测试 ==========
");
// 创建高优先级线程
Thread highPriority = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("【高优先级】线程执行: " + i);
}
}, "High-Priority");
highPriority.setPriority(Thread.MAX_PRIORITY); // 优先级10
// 创建低优先级线程
Thread lowPriority = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("【低优先级】线程执行: " + i);
}
}, "Low-Priority");
lowPriority.setPriority(Thread.MIN_PRIORITY); // 优先级1
// 创建普通优先级线程
Thread normalPriority = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("【普通优先级】线程执行: " + i);
}
}, "Normal-Priority");
normalPriority.setPriority(Thread.NORM_PRIORITY); // 优先级5
// 同时启动
lowPriority.start();
normalPriority.start();
highPriority.start();
// 等待所有线程执行完毕
lowPriority.join();
normalPriority.join();
highPriority.join();
System.out.println("
注意:优先级只是建议,不保证执行顺序!");
}
}
四、线程安全问题演示与测试
4.1 线程安全问题演示
当多个线程同时访问共享数据时,如果没有同步机制,就会出现数据不一致的问题。
java
/**
* 线程安全问题演示
* 多个线程同时操作共享变量,导致数据不一致
*/
public class ThreadSafetyProblem {
// 共享计数器
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 线程安全问题演示 ==========
");
System.out.println("初始值: counter = 0");
System.out.println("期望结果: counter = 10000
");
// 创建100个线程,每个线程对counter自增100次
Thread[] threads = new Thread[100];
for (int i = 0; i < 100; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
counter++; // 非原子操作,存在线程安全问题
}
}, "Thread-" + i);
threads[i].start();
}
// 等待所有线程执行完毕
for (Thread thread : threads) {
thread.join();
}
System.out.println("最终计数器值: " + counter);
System.out.println("期望值: 10000");
System.out.println("是否一致: " + (counter == 10000));
if (counter != 10000) {
System.out.println("
❌ 出现线程安全问题!丢失: " + (10000 - counter) + " 次自增");
}
}
}
运行结果(多次执行结果不同):
========== 线程安全问题演示 ==========
初始值: counter = 0
期望结果: counter = 10000
最终计数器值: 9823
期望值: 10000
是否一致: false
❌ 出现线程安全问题!丢失: 177 次自增
再次运行:
最终计数器值: 9567
期望值: 10000
是否一致: false
❌ 出现线程安全问题!丢失: 433 次自增
4.2 问题分析
counter++操作实际上分为三步:
- 读取:从内存读取counter的值到寄存器
- 修改:寄存器中的值加1
- 写入:将新值写回内存
当多个线程同时执行时,可能出现以下情况:
时间线:
线程A: 读取counter=0 → 寄存器+1=1 → [被抢占] → [恢复] → 写入counter=1
线程B: 读取counter=0 → 寄存器+1=1 → 写入counter=1
结果: counter=1 (期望是2)
这就是典型的**竞态条件(Race Condition)**问题。
4.3 使用synchronized修复
java
/**
* 使用synchronized修复线程安全问题
*/
public class SynchronizedFixTest {
private static int counter = 0;
private static final Object lock = new Object();
public static void main(String[] args) throws InterruptedException {
System.out.println("========== synchronized修复测试 ==========
");
Thread[] threads = new Thread[100];
for (int i = 0; i < 100; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
synchronized (lock) { // 加锁保证原子性
counter++;
}
}
}, "Thread-" + i);
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("最终计数器值: " + counter);
System.out.println("期望值: 10000");
System.out.println("是否一致: " + (counter == 10000));
if (counter == 10000) {
System.out.println("
✅ 线程安全问题已修复!");
}
}
}
运行结果:
========== synchronized修复测试 ==========
最终计数器值: 10000
期望值: 10000
是否一致: true
✅ 线程安全问题已修复!
4.4 使用AtomicInteger修复
java
import java.util.concurrent.atomic.AtomicInteger;
/**
* 使用AtomicInteger修复线程安全问题
*/
public class AtomicIntegerFixTest {
private static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
System.out.println("========== AtomicInteger修复测试 ==========
");
Thread[] threads = new Thread[100];
for (int i = 0; i < 100; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 100; j++) {
counter.incrementAndGet(); // CAS原子操作
}
}, "Thread-" + i);
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("最终计数器值: " + counter.get());
System.out.println("期望值: 10000");
System.out.println("是否一致: " + (counter.get() == 10000));
if (counter.get() == 10000) {
System.out.println("
✅ 使用CAS原子操作修复成功!");
}
}
}
运行结果:
========== AtomicInteger修复测试 ==========
最终计数器值: 10000
期望值: 10000
是否一致: true
✅ 使用CAS原子操作修复成功!
五、多线程性能测试
5.1 单线程 vs 多线程性能对比
java
/**
* 单线程与多线程性能对比测试
*/
public class PerformanceCompareTest {
private static final int COUNT = 100000000; // 1亿次计算
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 性能对比测试 ==========
");
// 单线程测试
long start1 = System.currentTimeMillis();
long sum1 = 0;
for (int i = 0; i < COUNT; i++) {
sum1 += i;
}
long end1 = System.currentTimeMillis();
System.out.println("单线程结果: " + sum1);
System.out.println("单线程耗时: " + (end1 - start1) + "ms
");
// 多线程测试(4个线程)
long start2 = System.currentTimeMillis();
Thread[] threads = new Thread[4];
long[] sums = new long[4];
for (int t = 0; t < 4; t++) {
final int threadIndex = t;
threads[t] = new Thread(() -> {
long partialSum = 0;
int start = threadIndex * (COUNT / 4);
int end = (threadIndex + 1) * (COUNT / 4);
for (int i = start; i < end; i++) {
partialSum += i;
}
sums[threadIndex] = partialSum;
});
threads[t].start();
}
for (Thread t : threads) {
t.join();
}
long sum2 = sums[0] + sums[1] + sums[2] + sums[3];
long end2 = System.currentTimeMillis();
System.out.println("多线程结果: " + sum2);
System.out.println("多线程耗时: " + (end2 - start2) + "ms
");
System.out.println("性能提升: " + (end1 - start1) / (double)(end2 - start2) + "x");
}
}
运行结果(4核CPU):
========== 性能对比测试 ==========
单线程结果: 4999999950000000
单线程耗时: 320ms
多线程结果: 4999999950000000
多线程耗时: 95ms
性能提升: 3.37x
5.2 线程创建开销测试
java
/**
* 线程创建开销测试
* 对比直接创建线程和使用线程池的性能差异
*/
public class ThreadCreationOverheadTest {
private static final int TASK_COUNT = 1000;
public static void main(String[] args) throws InterruptedException {
System.out.println("========== 线程创建开销测试 ==========
");
// 方法1:直接创建线程
long start1 = System.currentTimeMillis();
Thread[] threads = new Thread[TASK_COUNT];
for (int i = 0; i < TASK_COUNT; i++) {
threads[i] = new Thread(() -> {
// 简单任务
int sum = 0;
for (int j = 0; j < 100; j++) {
sum += j;
}
});
threads[i].start();
}
for (Thread t : threads) {
t.join();
}
long end1 = System.currentTimeMillis();
System.out.println("直接创建" + TASK_COUNT + "个线程耗时: " + (end1 - start1) + "ms");
// 方法2:使用线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
long start2 = System.currentTimeMillis();
for (int i = 0; i < TASK_COUNT; i++) {
executor.execute(() -> {
int sum = 0;
for (int j = 0; j < 100; j++) {
sum += j;
}
});
}
executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);
long end2 = System.currentTimeMillis();
System.out.println("使用线程池(10线程)耗时: " + (end2 - start2) + "ms");
System.out.println("
结论:线程池可以显著减少线程创建销毁的开销!");
}
}
运行结果:
========== 线程创建开销测试 ==========
直接创建1000个线程耗时: 1567ms
使用线程池(10线程)耗时: 234ms
结论:线程池可以显著减少线程创建销毁的开销!
六、线程调试技巧
6.1 IDEA多线程调试
在IntelliJ IDEA中调试多线程程序:
- 在断点处右键,选择"Suspend" -> "Thread"
- 在Debug窗口的"Threads"标签页查看所有线程状态
- 可以切换不同线程进行单步调试

6.2 使用jstack查看线程状态
bash
# 查看Java进程的线程堆栈
jstack -l <pid>
# 示例输出:
"Worker-0" #11 prio=5 os_prio=0 tid=0x00007f8b0c0d1800 nid=0x3e03 waiting on condition [0x000070000b5a5000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at BasicMultiThreadTest.lambda$main$0(BasicMultiThreadTest.java:15)
at BasicMultiThreadTest$$Lambda$1/791452441.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
6.3 使用jconsole监控线程
bash
jconsole
可以可视化查看:
- 线程数量变化
- 线程状态分布
- 死锁检测

七、总结
本文详细介绍了Java多线程的基础内容:
- 线程生命周期:6种状态及其转换条件
- 多线程并发测试:基础并发执行、执行顺序、优先级测试
- 线程安全问题:竞态条件演示、synchronized和AtomicInteger修复方案
- 性能测试:单线程vs多线程、线程创建开销对比
- 调试技巧:IDEA调试、jstack、jconsole工具使用
后续文章将继续深入讲解线程池、JUC并发工具类、CompletableFuture异步编程等高级内容,敬请期待!
如果觉得本文对你有帮助,欢迎点赞、收藏、评论!
关注博主,持续更新Java技术干货!