一、线程的生命周期与状态转换
线程在其生命周期中会经历多个状态,理解这些状态及其转换对于正确使用多线程至关重要。
线程状态
public class ThreadStates {
public static void main(String[] args) throws InterruptedException {
// NEW:新建状态
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("新建状态:" + thread.getState()); // NEW
// RUNNABLE:运行状态
thread.start();
System.out.println("运行状态:" + thread.getState()); // RUNNABLE
// TIMED_WAITING:计时等待
Thread.sleep(100);
System.out.println("等待状态:" + thread.getState()); // TIMED_WAITING
// 等待线程结束
thread.join();
System.out.println("终止状态:" + thread.getState()); // TERMINATED
}
}
线程的基本操作
public class ThreadOperations {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
// 检查中断状态
while (!Thread.currentThread().isInterrupted()) {
// 线程执行的操作
System.out.println("线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 重新设置中断状态
Thread.currentThread().interrupt();
}
}
});
thread.start();
// 设置优先级
thread.setPriority(Thread.MAX_PRIORITY);
// 中断线程
thread.interrupt();
}
}
二、线程池的工作原理与使用
线程池通过重用线程来减少线程创建和销毁的开销。
线程池的创建与使用
public class ThreadPoolExample {
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService fixedPool = Executors.newFixedThreadPool(5);
// 创建缓存线程池
ExecutorService cachedPool = Executors.newCachedThreadPool();
// 创建自定义线程池
ThreadPoolExecutor customPool = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60L, // 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(100), // 工作队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 提交任务
customPool.submit(() -> {
System.out.println("任务执行中...");
return "任务结果";
});
// 关闭线程池
customPool.shutdown();
}
}
三、synchronized同步机制
synchronized用于实现线程同步,保证代码块或方法在同一时刻只能被一个线程执行。
synchronized的使用方式
public class SynchronizedExample {
private int count = 0;
private final Object lock = new Object();
// 同步方法
public synchronized void increment() {
count++;
}
// 同步代码块
public void incrementBlock() {
synchronized (lock) {
count++;
}
}
// 静态同步方法
public static synchronized void staticMethod() {
System.out.println("静态同步方法");
}
// 实际应用示例
public void process() {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
increment();
}
});
t1.start();
t2.start();
// 等待线程完成
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最终计数: " + count);
}
}
四、volatile关键字
volatile保证了变量的可见性和有序性,但不保证原子性。
volatile的使用场景
public class VolatileExample {
// volatile确保可见性
private volatile boolean flag = false;
public void writer() {
flag = true; // 修改后其他线程立即可见
}
public void reader() {
while (!flag) {
// 等待flag变为true
}
}
// 双重检查锁定模式
private static volatile VolatileExample instance;
public static VolatileExample getInstance() {
if (instance == null) {
synchronized (VolatileExample.class) {
if (instance == null) {
instance = new VolatileExample();
}
}
}
return instance;
}
}
五、原子类
原子类提供了线程安全的操作,无需使用synchronized。
常用原子类操作
public class AtomicExample {
// 原子整数
private AtomicInteger counter = new AtomicInteger(0);
// 原子引用
private AtomicReference<String> reference =
new AtomicReference<>("initial");
// 原子数组
private AtomicIntegerArray array = new AtomicIntegerArray(10);
public void atomicOperations() {
// 增加并获取
int value = counter.incrementAndGet();
// 比较并设置
reference.compareAndSet("initial", "updated");
// 数组操作
array.getAndAdd(0, 1);
}
// 复杂的原子操作
public void complexAtomicOperation() {
counter.updateAndGet(x -> x * 2);
counter.accumulateAndGet(10, Integer::sum);
}
}
最佳实践建议 💡
- 线程创建与管理
- 优先使用线程池而不是直接创建线程
- 正确处理线程中断
- 避免使用Thread.stop()等过时方法
- 同步处理
- 最小化同步范围
- 优先使用java.util.concurrent包中的工具类
- 注意死锁预防
- 性能优化
- 合理设置线程池参数
- 避免过度同步
- 使用适当的并发容器
常见陷阱提醒 ⚠️
- 同步问题
// 错误:非原子操作
private volatile int count = 0;
public void increment() {
count++; // 非原子操作
}
// 正确:使用原子类
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
- 线程池问题
// 错误:使用无界队列
ExecutorService executor = new ThreadPoolExecutor(
10, 10, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>()); // 可能导致OOM
// 正确:使用有界队列
ExecutorService executor = new ThreadPoolExecutor(
10, 10, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000));
- 死锁问题
// 可能导致死锁的代码
public class DeadlockExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
synchronized (lock2) {
// 操作
}
}
}
public void method2() {
synchronized (lock2) {
synchronized (lock1) {
// 操作
}
}
}
}
并发编程是Java中最复杂的主题之一,正确理解和使用这些概念对于开发高性能、可靠的应用程序至关重要。记住要注意线程安全性、性能和死锁预防。