抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

前言

Java 多线程编程是提高程序性能和响应能力的关键技术,但也涉及到复杂的并发问题。以下是一个结构化的知识总结。

线程与进程

  • 进程:独立运行的程序实例,拥有独立的内存空间。
  • 线程:进程内的执行单元,共享进程的资源,切换开销更小。
  • 区别:进程间隔离,线程共享内存;线程更轻量

创建线程的三种方式

继承 Thread

1
2
3
4
5
6
7
class MyThread extends Thread {
public void run() {
System.out.println("Thread running");
}
}
MyThread t = new MyThread();
t.start();

实现 Runnable 接口(推荐,避免单继承限制)

1
2
3
4
5
6
7
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable running");
}
}
Thread t = new Thread(new MyRunnable());
t.start();

实现 Callable 接口(可返回结果,配合 FutureTask 使用)

1
2
3
4
5
6
7
8
class MyCallable implements Callable<String> {
public String call() throws Exception {
return "Callable result";
}
}
FutureTask<String> task = new FutureTask<>(new MyCallable());
new Thread(task).start();
String result = task.get(); // 阻塞获取结果

线程生命周期(状态)

  • 新建(New):线程对象创建后未启动。
  • 就绪(Runnable):调用 start() 后,等待CPU调度。
  • 运行(Running):执行 run() 方法。
  • 阻塞(Blocked):等待锁(如进入同步代码块)。
  • 等待(Waiting):无期限等待,需其他线程唤醒(如 Object.wait())。
  • 超时等待(Timed Waiting):有限时间等待(如 Thread.sleep(ms))。
  • 终止(Terminated)run() 执行完毕或异常退出。

线程同步与通信

同步机制

  • synchronized 关键字:修饰方法或代码块,确保原子性。
  • Lock 接口(如 ReentrantLock):更灵活,支持尝试锁、公平锁。
  • volatile 变量:保证可见性,禁止指令重排序,但不保证原子性。

线程通信

  • wait()/notify()/notifyAll():需在同步块内调用,避免虚假唤醒。
  • BlockingQueue:线程安全队列,实现生产者-消费者模式。

线程池(Executor框架)

核心类

  • ExecutorService:管理线程池生命周期。
  • ThreadPoolExecutor:可配置核心参数(核心线程数、最大线程数、队列、拒绝策略)。

常见线程池

  • FixedThreadPool:固定线程数,适用于负载稳定场景。
  • CachedThreadPool:线程数弹性伸缩,适合短时异步任务。
  • SingleThreadExecutor:单线程顺序执行任务。

拒绝策略

AbortPolicy(抛异常)、CallerRunsPolicy(调用者执行任务)。

并发工具类

  • ConcurrentHashMap:分段锁实现高并发访问。
  • CopyOnWriteArrayList:写时复制,读操作无锁。
  • 原子类(如 AtomicInteger):CAS操作实现无锁线程安全。
  • CountDownLatch:等待多个任务完成。
  • CyclicBarrier:多线程到达屏障后继续执行。

高级主题

  • Fork/Join框架:分治策略,适用于可拆分的计算密集型任务。
  • CompletableFuture(Java 8+):链式异步编程,支持组合多个异步操作。
  • ThreadLocal:线程局部变量,需注意内存泄漏(使用后及时调用 remove())。

避免并发问题

  • 死锁预防:避免嵌套锁、按顺序获取锁、设置超时(如 tryLock)。
  • 内存可见性:使用 volatile 或同步机制确保修改可见。
  • 资源竞争:优先使用线程安全的数据结构(如 ConcurrentHashMap)。

调试与监控

  • 线程转储(Thread Dump):通过 jstack 或可视化工具(如 VisualVM)分析死锁。
  • 日志记录:跟踪线程执行流程,定位竞态条件。

后记

在多线程的应用中,尽量做到:

  • 减少锁粒度:尽量缩小同步代码块。
  • 使用线程池:避免频繁创建/销毁线程。
  • 避免共享状态:优先使用不可变对象或线程局部变量。
  • 优先使用高层抽象:如 ExecutorConcurrent Collections,而非直接操作线程。

评论