一、线程的生命周期与状态转换
线程在其生命周期中会经历多个状态,理解这些状态及其转换对于正确使用多线程至关重要。
线程状态
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中最复杂的主题之一,正确理解和使用这些概念对于开发高性能、可靠的应用程序至关重要。记住要注意线程安全性、性能和死锁预防。