Java 多线程是 Java 并发编程的核心内容之一,掌握多线程相关的知识点对于编写高效、稳定的并发程序至关重要。以下是 Java 多线程的主要知识点:
1. 线程的基本概念
- 线程:程序执行的最小单位,是进程中的一个独立控制流。
- 进程 vs 线程:进程是资源分配的基本单位,线程是 CPU 调度的基本单位。一个进程可以包含多个线程。
- 多线程的优势:提高程序效率,充分利用 CPU 资源,改善用户体验。
2. 线程的创建方式
Java 提供了多种创建线程的方式:
- 继承
Thread
类class MyThread extends Thread { @Override public void run() { System.out.println("Thread is running"); } } MyThread thread = new MyThread(); thread.start();
- 实现
Runnable
接口class MyRunnable implements Runnable { @Override public void run() { System.out.println("Thread is running"); } } Thread thread = new Thread(new MyRunnable()); thread.start();
- 实现
Callable
接口(带返回值)class MyCallable implements Callable<String> { @Override public String call() throws Exception { return "Task completed"; } } FutureTask<String> futureTask = new FutureTask<>(new MyCallable()); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.get()); // 获取返回值
- 使用线程池(推荐)
ExecutorService executor = Executors.newFixedThreadPool(5); executor.submit(() -> System.out.println("Task running")); executor.shutdown();
3. 线程的生命周期
线程的生命周期包括以下状态:
- NEW:线程刚创建,尚未启动。
- RUNNABLE:线程正在运行或等待 CPU 资源。
- BLOCKED:线程被阻塞,等待获取锁。
- WAITING:线程无限期等待,直到被其他线程唤醒。
- TIMED_WAITING:线程等待指定时间。
- TERMINATED:线程执行完毕。
4. 线程同步与锁
多线程环境下,共享资源的访问需要同步,以避免数据不一致问题。
- synchronized 关键字
- 修饰方法或代码块,确保同一时间只有一个线程访问。
public synchronized void method() { // 同步代码 }
- ReentrantLock
- 显式锁,比
synchronized
更灵活,支持公平锁和非公平锁。
ReentrantLock lock = new ReentrantLock(); lock.lock(); try { // 同步代码 } finally { lock.unlock(); }
- 显式锁,比
- volatile 关键字
- 保证变量的可见性,但不保证原子性。
private volatile boolean flag = false;
5. 线程间通信
- wait() 和 notify()
wait()
:让当前线程进入等待状态,释放锁。notify()
:唤醒一个等待的线程。
synchronized (obj) { while (condition) { obj.wait(); } // 执行任务 obj.notify(); }
- BlockingQueue
- 线程安全的队列,常用于生产者-消费者模型。
BlockingQueue<String> queue = new LinkedBlockingQueue<>(); queue.put("data"); // 生产者 String data = queue.take(); // 消费者
6. 线程池
线程池是管理线程的工具,可以避免频繁创建和销毁线程的开销。
- 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
- 提交任务
executor.submit(() -> System.out.println("Task running"));
- 关闭线程池
executor.shutdown();
- ThreadPoolExecutor
- 自定义线程池的核心参数:
- 核心线程数
- 最大线程数
- 空闲线程存活时间
- 任务队列
- 拒绝策略
- 自定义线程池的核心参数:
7. 并发工具类
Java 提供了丰富的并发工具类:
- CountDownLatch
- 等待多个线程完成任务。
CountDownLatch latch = new CountDownLatch(3); latch.await(); // 等待 latch.countDown(); // 计数减一
- CyclicBarrier
- 让一组线程互相等待,达到屏障点后继续执行。
CyclicBarrier barrier = new CyclicBarrier(3); barrier.await(); // 等待其他线程
- Semaphore
- 控制同时访问资源的线程数量。
Semaphore semaphore = new Semaphore(5); semaphore.acquire(); // 获取许可 semaphore.release(); // 释放许可
- Exchanger
- 用于两个线程之间交换数据。
8. 原子类
Java 提供了 java.util.concurrent.atomic
包,支持无锁的原子操作。
- AtomicInteger
AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.incrementAndGet(); // 原子自增
- AtomicReference
AtomicReference<String> atomicRef = new AtomicReference<>("initial"); atomicRef.compareAndSet("initial", "updated"); // CAS 操作
9. Fork/Join 框架
用于并行执行任务的框架,适合分治算法。
class MyTask extends RecursiveTask<Integer> {
@Override
protected Integer compute() {
// 任务逻辑
return result;
}
}
ForkJoinPool pool = new ForkJoinPool();
MyTask task = new MyTask();
pool.invoke(task);
10. 线程安全集合
Java 提供了线程安全的集合类:
- CopyOnWriteArrayList
- 写时复制的列表。
- ConcurrentHashMap
- 高效的并发哈希表。
- BlockingQueue
- 线程安全的队列。
11. 线程的异常处理
线程的异常不能跨线程传播,需要通过以下方式处理:
- UncaughtExceptionHandler
Thread thread = new Thread(() -> { throw new RuntimeException("Exception in thread"); }); thread.setUncaughtExceptionHandler((t, e) -> { System.out.println("Exception caught: " + e.getMessage()); }); thread.start();
12. 线程的优先级
- 通过
setPriority(int priority)
设置线程优先级(1-10)。 - 优先级高的线程更有可能被调度执行,但不保证。
13. 守护线程
- 通过
setDaemon(true)
将线程设置为守护线程。 - 守护线程在 JVM 中没有非守护线程时自动终止。
14. CompletableFuture
- 用于异步编程,支持链式调用和组合多个异步任务。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello");
future.thenAccept(System.out::println);
总结
Java 多线程涉及的知识点非常广泛,包括线程创建、同步、通信、线程池、并发工具类等。掌握这些知识点可以帮助你编写高效、安全的并发程序。在实际开发中,建议优先使用线程池和并发工具类,避免直接操作线程。