Java多线程是指在一个程序中同时运行多个执行路径,可提升CPU利用率和程序响应性。以下是核心内容:
一、多线程实现方式
1. 继承 Thread 类
- 重写 run() 方法定义线程任务。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程执行中:" + getName());
}
}
// 使用
MyThread thread = new MyThread();
thread.start(); // 启动线程,而非直接调用run()
2. 实现 Runnable 接口
- 更灵活(避免单继承限制),推荐使用。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable线程执行");
}
}
// 使用
Thread thread = new Thread(new MyRunnable());
thread.start();
3. 实现 Callable 接口(Java 5+)
- 支持返回值和抛出异常,需配合 Future 获取结果。
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1 + 1; // 可返回计算结果
}
}
// 使用
FutureTask<Integer> future = new FutureTask<>(new MyCallable());
new Thread(future).start();
Integer result = future.get(); // 阻塞获取结果
二、线程状态与生命周期
线程状态转换图(简化) → 运行(Running) → 阻塞(Blocked) → 等待(Waiting) → 超时等待(Timed_Waiting) → 终止(Terminated)
三、线程控制与常用方法
1. 线程调度
- Thread.sleep(long ms) :让当前线程休眠指定毫秒数。
- Thread.yield() :主动让出CPU,回到就绪状态。
- join() :等待其他线程执行完毕,如 thread.join() 会阻塞当前线程直到 thread 结束。
2. 线程优先级
- setPriority(int priority) :设置优先级(1-10,默认5),高优先级线程获更多执行机会。
3. 守护线程(Daemon Thread)
- setDaemon(true) :当所有非守护线程结束时,守护线程自动终止(如垃圾回收线程)。
四、线程安全与同步机制
1. 线程安全问题
- 当多个线程同时访问共享资源(如变量、文件)时,可能导致数据不一致(如i++操作非原子性)。
2. 同步方案
- synchronized关键字:
- 同步代码块: synchronized(锁对象) { ... } (锁对象需为共享资源)。
- 同步方法:在方法声明前加 synchronized ,锁对象为 this 。
// 同步代码块示例
private Object lock = new Object();
public void safeMethod() {
synchronized (lock) {
// 线程安全的操作
}
}
- ReentrantLock(可重入锁,Java 5+):
- 比 synchronized 更灵活,支持公平锁、超时等待等。
import java.util.concurrent.locks.ReentrantLock;
private ReentrantLock lock = new ReentrantLock();
public void safeMethod() {
lock.lock(); // 加锁
try {
// 操作
} finally {
lock.unlock(); // 解锁(必须在finally中,避免异常导致死锁)
}
}
3. 原子类(java.util.concurrent.atomic)
- 如 AtomicInteger 、 AtomicReference ,通过CAS( compare-and-swap)实现无锁原子操作:
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 原子性i++
五、线程通信与协作
1. wait/notify/notifyAll(配合synchronized)
- wait() :让线程进入等待状态,释放锁。
- notify() :唤醒一个等待中的线程。
- notifyAll() :唤醒所有等待中的线程。
// 生产者-消费者示例(简化)
private final Object lock = new Object();
private int productCount = 0;
// 生产者
public void produce() {
synchronized (lock) {
while (productCount >= 10) { // 避免虚假唤醒,用while判断
lock.wait(); // 等待消费者消费
}
productCount++;
lock.notifyAll(); // 通知消费者
}
}
// 消费者
public void consume() {
synchronized (lock) {
while (productCount <= 0) {
lock.wait(); // 等待生产者生产
}
productCount--;
lock.notifyAll(); // 通知生产者
}
}
2. Condition(配合ReentrantLock)
- 比 wait/notify 更灵活,可实现多条件等待。
private ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void method() {
lock.lock();
try {
condition.await(); // 等待
condition.signal(); // 唤醒一个线程
} finally {
lock.unlock();
}
}
六、线程池(Java 5+,java.util.concurrent)
1. 核心优势
- 复用线程,避免频繁创建销毁线程的开销;控制线程数量,防止OOM。
2. 常用线程池
- Executors工厂方法:
- newFixedThreadPool(int nThreads) :固定大小线程池。
- newCachedThreadPool() :可伸缩线程池(空闲线程60秒后回收)。
- newSingleThreadExecutor() :单线程池(按顺序执行任务)。
- newScheduledThreadPool(int corePoolSize) :支持定时/延迟执行任务。
- 手动创建ThreadPoolExecutor(推荐,更可控):
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
// corePoolSize=2,最大线程数=5,空闲线程存活时间=60秒,任务队列容量=10
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 5, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
new ThreadFactory() { // 自定义线程创建
private int count = 1;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "MyThread-" + count++);
}
},
new ThreadPoolExecutor.AbortPolicy() // 任务拒绝策略:默认抛出异常
);
// 提交任务
executor.execute(() -> System.out.println("异步任务"));
executor.submit(() -> { // 带返回值的任务
System.out.println("有返回值的任务");
return "结果";
});
// 关闭线程池
executor.shutdown(); // 平滑关闭,不接受新任务,处理完已提交任务
executor.shutdownNow(); // 立即关闭,尝试中断正在执行的任务
七、并发工具类(java.util.concurrent)
1. CountDownLatch
- 允许一个线程等待其他线程完成操作:
CountDownLatch latch = new CountDownLatch(3); // 初始化计数器为3
// 线程1-3完成后计数减1
new Thread(() -> { latch.countDown(); }).start();
new Thread(() -> { latch.countDown(); }).start();
new Thread(() -> { latch.countDown(); }).start();
// 主线程等待计数器归零
latch.await(); // 阻塞直到countDown到0
System.out.println("所有线程已完成");
2. CyclicBarrier
- 让一组线程等待至某个屏障点再一起执行:
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程到达屏障,开始执行汇总任务");
});
// 3个线程各自执行任务,到达barrier时等待
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + " 准备到达屏障");
barrier.await(); // 等待其他线程
System.out.println(Thread.currentThread().getName() + " 继续执行");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
3. Semaphore
- 控制同时访问资源的线程数量(如限流):
Semaphore semaphore = new Semaphore(2); // 最多2个线程同时访问
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可,无许可时阻塞
System.out.println(Thread.currentThread().getName() + " 获得许可,访问资源");
Thread.sleep(1000); // 模拟访问资源
System.out.println(Thread.currentThread().getName() + " 释放资源");
} catch (Exception e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可
}
}).start();
}
八、多线程开发最佳实践
1. 避免死锁:
- 按统一顺序获取锁,避免嵌套锁;使用 ReentrantLock 的 tryLock() 尝试获取锁并设置超时。
2. 优先使用线程池:避免手动创建大量线程,通过 ThreadPoolExecutor 自定义参数。
3. 减少同步范围:仅对共享资源加锁,避免同步整个方法。
4. 合理处理中断:通过 isInterrupted() 判断线程是否被中断,避免直接调用 stop() (已过时,可能导致资源未释放)。
5. 使用原子类替代同步:对简单操作(如计数)优先用 AtomicInteger 等原子类,提升性能。
总结
Java多线程通过 Thread 、 Runnable 等实现任务并行,结合 synchronized 、 ReentrantLock 解决线程安全问题,利用线程池和并发工具类提升开发效率。实际开发中需重点关注线程安全、性能优化和资源管理,避免死锁、竞态条件等问题。
10万+

被折叠的 条评论
为什么被折叠?



