目录
一、线程基础
-
线程 vs 进程
- 进程:独立的程序执行单元,拥有独立的内存空间。
- 线程:进程内的子任务,共享进程的内存空间,切换成本低。
-
创建线程的两种方式
-
继承
Thread
类class MyThread extends Thread { @Override public void run() { System.out.println("Thread is running"); } } // 启动线程 MyThread t = new MyThread(); t.start();
-
实现
Runnable
接口(推荐,避免单继承限制)class MyRunnable implements Runnable { @Override public void run() { System.out.println("Runnable is running"); } } // 启动线程 Thread t = new Thread(new MyRunnable()); t.start();
-
二、 线程生命周期
线程可能处于以下状态:
- NEW(新建)
- RUNNABLE(可运行/就绪)
- RUNNING(运行中)
- BLOCKED(阻塞,如等待锁)
- WAITING(无限期等待)
- TIMED_WAITING(超时等待)
- TERMINATED(终止)
- 状态转换:
NEW
→RUNNABLE
→RUNNING
→BLOCKED
/WAITING
/TIMED_WAITING
→TERMINATED
- 关键方法:
start()
、run()
、sleep()
、yield()
、join()
、interrupt()
。
三、线程同步与锁
1. 线程安全问题
- 根源:多个线程共享数据时,操作非原子性导致数据不一致(如卖票超卖)。
2. 同步机制
-
synchronized
关键字- 修饰方法或代码块,保证同一时刻仅一个线程访问。
// 同步方法 public synchronized void syncMethod() { ... } // 同步代码块 synchronized (lockObject) { // 临界区代码 }
-
ReentrantLock
显式锁Lock lock = new ReentrantLock(); lock.lock(); try { // 临界区代码 } finally { lock.unlock(); }
3. volatile
关键字
- 保证变量可见性(直接读写主内存),禁止指令重排序,但不保证原子性。
private volatile boolean flag = false;
四、线程间通信
1. wait()
和 notify()
- 必须在
synchronized
块中使用,释放锁并等待唤醒。synchronized (lock) { lock.wait(); // 释放锁,进入等待 lock.notifyAll(); // 唤醒所有等待线程 }
2. Condition
接口
- 配合
ReentrantLock
使用,更灵活的等待/唤醒机制。Lock lock = new ReentrantLock(); Condition condition = lock.newCondition(); lock.lock(); try { condition.await(); // 类似 wait() condition.signal(); // 类似 notify() } finally { lock.unlock(); }
五、线程池与并发工具
1. 线程池(ExecutorService
)
使用线程池避免频繁创建/销毁线程的开销。
- 核心参数:
corePoolSize
:核心线程数maximumPoolSize
:最大线程数keepAliveTime
:非核心线程的空闲存活时间workQueue
:任务队列(如LinkedBlockingQueue
)
- 常用线程池:
ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(() -> { System.out.println("Task executed by thread pool"); }); executor.shutdown(); // 关闭线程池
2. 并发工具类
-
CountDownLatch
:等待多个线程完成任务。CountDownLatch latch = new CountDownLatch(3); latch.await(); // 等待计数归零 latch.countDown(); // 计数减1
-
CyclicBarrier
:多个线程到达屏障后继续执行。CyclicBarrier barrier = new CyclicBarrier(3, () -> { System.out.println("All threads reached the barrier"); }); barrier.await(); // 等待其他线程
-
Semaphore
:控制同时访问资源的线程数。Semaphore semaphore = new Semaphore(3); semaphore.acquire(); // 获取许可 semaphore.release(); // 释放许可
六、高级特性与最佳实践
1. 原子类(AtomicInteger
等)
- 保证操作的原子性(如
incrementAndGet()
)。AtomicInteger counter = new AtomicInteger(0); counter.incrementAndGet();
2. 并发集合
- 替代同步集合,提升性能:
ConcurrentHashMap
、CopyOnWriteArrayList
、BlockingQueue
。
3. 异步编程(CompletableFuture
)
- 链式调用处理异步任务。
CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") .thenAccept(System.out::println);
4. 并行流(Parallel Streams)
- 将列表转换为并行流,遍历流中的每个元素并打印。
List<Integer> list = Arrays.asList(1, 2, 3); list.parallelStream().forEach(System.out::println);
5. 避免死锁
- 条件:互斥、持有并等待、不可抢占、循环等待。
- 解决:按顺序获取锁、使用
tryLock()
超时机制。
6. 线程中断
- 通过
interrupt()
请求终止线程,线程需检查中断状态。if (Thread.currentThread().isInterrupted()) { // 清理资源并退出 }
七、Java 内存模型(JMM)
1. 主内存与工作内存
- 线程对变量的操作在工作内存中进行,最终同步到主内存。
2. Happens-Before 原则
- 确保一个线程的操作对另一个线程可见(如
synchronized
、volatile
)。
八、应用场景
- 高并发任务处理(如 Web 服务器处理请求)。
- 异步任务执行(如后台日志写入、邮件发送)。
- 并行计算(如大数据处理、图像渲染)。
- 定时任务调度(如
ScheduledExecutorService
)。
总结
- 核心掌握:线程同步、锁机制、线程池、并发工具类。
- 避免误区:过度依赖
synchronized
(注意性能)、忽略线程中断机制。 - 学习路径:基础 → 同步 → 线程池 → 并发工具 → 高级特性 → 实战项目(如实现下载器、爬虫)。