深入理解并发编程的基础概念
本页系统讲解线程与进程的区别、Java 线程的创建方式、线程状态转换等核心知识点。
简单记忆:进程是资源的容器,线程是执行的最小单位。
优点:
缺点:
四种方式:
// 1. 继承 Thread 类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running");
}
}
new MyThread().start();
// 2. 实现 Runnable 接口(推荐)
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running");
}
}
new Thread(new MyRunnable()).start();
// 3. 实现 Callable 接口(有返回值)
class MyCallable implements Callable {
@Override
public String call() throws Exception {
return "Callable result";
}
}
FutureTask task = new FutureTask<>(new MyCallable());
new Thread(task).start();
String result = task.get();
// 4. 使用线程池(推荐)
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(() -> System.out.println("Thread pool")); // Runnable:无返回值
Runnable runnable = () -> {
System.out.println("No return value");
};
// Callable:有返回值
Callable callable = () -> {
return 42; // 可以返回结果
};
// 使用 FutureTask 获取 Callable 的结果
FutureTask task = new FutureTask<>(callable);
new Thread(task).start();
Integer result = task.get(); // 阻塞等待结果 六种状态(Thread.State):
// sleep:不释放锁
synchronized (lock) {
Thread.sleep(1000); // 持有锁,其他线程无法进入
}
// wait:释放锁
synchronized (lock) {
lock.wait(); // 释放锁,其他线程可以进入
// 被 notify() 唤醒后继续执行
}Thread thread = new Thread(() -> {
System.out.println("Thread: " + Thread.currentThread().getName());
});
thread.start(); // 输出:Thread: Thread-0(新线程)
thread.run(); // 输出:Thread: main(当前线程)作用:等待线程执行完毕。
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("Thread finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
thread.join(); // 主线程等待 thread 执行完毕
System.out.println("Main finished");
// 输出顺序:
// Thread finished
// Main finished应用场景:需要等待子线程完成后再继续执行(如汇总多个线程的计算结果)。
推荐方式:使用中断标志
// ❌ 不推荐:stop() 方法已废弃
thread.stop(); // 强制停止,可能导致数据不一致
// ✅ 推荐:使用 interrupt() + 检查中断标志
class MyThread extends Thread {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// 捕获中断异常后,重新设置中断标志
Thread.currentThread().interrupt();
break;
}
}
// 清理资源
}
}
MyThread thread = new MyThread();
thread.start();
thread.interrupt(); // 请求中断定义:守护线程是为其他线程提供服务的后台线程,当所有非守护线程结束时,JVM 会退出,守护线程也会被强制终止。
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("Daemon running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
});
daemon.setDaemon(true); // 设置为守护线程
daemon.start();
// 主线程结束后,守护线程也会自动终止应用场景:
线程安全:多线程访问共享资源时,程序能正确执行,不会产生数据不一致或异常。
// 1. synchronized 关键字
public synchronized void increment() { count++; }
// 2. Lock 接口
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try { count++; } finally { lock.unlock(); }
}
// 3. 原子类
private AtomicInteger count = new AtomicInteger(0);
public void increment() { count.incrementAndGet(); }// Lock 的高级特性示例
ReentrantLock lock = new ReentrantLock(true); // 公平锁
// 1. 可中断获取锁
lock.lockInterruptibly();
// 2. 超时获取锁
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try { /* 业务逻辑 */ } finally { lock.unlock(); }
}
// 3. 多条件变量
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();volatile 的两个作用:
// volatile 典型应用:状态标志
private volatile boolean running = true;
public void stop() { running = false; }
public void run() {
while (running) { /* 工作 */ }
}
// volatile 不能保证原子性!
private volatile int count = 0;
count++; // ❌ 非原子操作,线程不安全
// DCL 单例模式中的 volatile
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // 防止重排序
}
}
}
return instance;
}核心要点:必须在 synchronized 块内调用,且调用对象必须是锁对象。
// 生产者-消费者模型
class Buffer {
private Queue queue = new LinkedList<>();
private int capacity = 10;
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == capacity) {
wait(); // 队列满,等待消费者
}
queue.add(item);
notifyAll(); // 通知消费者
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // 队列空,等待生产者
}
int item = queue.poll();
notifyAll(); // 通知生产者
return item;
}
} 定义:ThreadLocal 为每个线程提供独立的变量副本,实现线程隔离。
// 典型应用:用户上下文
public class UserContext {
private static ThreadLocal userHolder = new ThreadLocal<>();
public static void setUser(User user) { userHolder.set(user); }
public static User getUser() { return userHolder.get(); }
public static void clear() { userHolder.remove(); } // 防止内存泄漏
}
// 使用示例
UserContext.setUser(currentUser);
try {
// 业务逻辑中随时获取用户
User user = UserContext.getUser();
} finally {
UserContext.clear(); // 必须清理!
} 应用场景:用户会话、数据库连接、日期格式化器、事务管理。
死锁四个必要条件:
// ❌ 死锁代码示例
Thread t1 = new Thread(() -> {
synchronized (lockA) {
Thread.sleep(100);
synchronized (lockB) { /* 业务 */ }
}
});
Thread t2 = new Thread(() -> {
synchronized (lockB) {
Thread.sleep(100);
synchronized (lockA) { /* 业务 */ }
}
});
// ✅ 避免死锁:固定加锁顺序
Thread t1 = new Thread(() -> {
synchronized (lockA) {
synchronized (lockB) { /* 业务 */ }
}
});
Thread t2 = new Thread(() -> {
synchronized (lockA) { // 相同顺序
synchronized (lockB) { /* 业务 */ }
}
});避免死锁的方法:
// 活锁示例:两个线程互相让步
while (true) {
if (other.isWaiting()) {
Thread.yield(); // 让步给对方
continue; // 但对方也在让步,导致都无法执行
}
// 执行业务
}
// 解决方案:引入随机等待时间
while (true) {
if (other.isWaiting()) {
Thread.sleep(random.nextInt(100)); // 随机等待
continue;
}
// 执行业务
}// 自定义线程池(推荐)
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, // 核心线程数
10, // 最大线程数
60, TimeUnit.SECONDS, // 空闲线程存活时间
new LinkedBlockingQueue<>(100), // 任务队列
new ThreadFactory() { // 自定义线程工厂
private AtomicInteger count = new AtomicInteger(0);
public Thread newThread(Runnable r) {
return new Thread(r, "MyThread-" + count.incrementAndGet());
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
// 线程数配置建议
// CPU密集型:N + 1(N为CPU核心数)
// IO密集型:2N 或 N / (1 - 阻塞系数)// 自定义拒绝策略
RejectedExecutionHandler handler = (r, executor) -> {
// 记录日志
log.warn("任务被拒绝: " + r.toString());
// 可选:持久化到数据库或消息队列
// 可选:重试机制
};// CountDownLatch:主线程等待多个子任务完成
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
executor.submit(() -> {
doTask();
latch.countDown(); // 完成一个任务
});
}
latch.await(); // 主线程等待所有任务完成
// CyclicBarrier:多个线程互相等待,同时开始
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程就绪,开始执行");
});
for (int i = 0; i < 3; i++) {
executor.submit(() -> {
prepare();
barrier.await(); // 等待其他线程
execute(); // 同时开始执行
});
}作用:控制同时访问资源的线程数量(限流)。
// 限制同时访问数据库的连接数
Semaphore semaphore = new Semaphore(10); // 最多10个并发
public void accessDatabase() {
try {
semaphore.acquire(); // 获取许可
// 访问数据库
} finally {
semaphore.release(); // 释放许可
}
}
// 应用场景:
// 1. 数据库连接池限流
// 2. 接口限流
// 3. 资源池管理// 方式1:双重检查锁(DCL)
public class Singleton {
private static volatile Singleton instance; // volatile 防止重排序
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
// 方式2:静态内部类(推荐)
public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE; // 类加载时初始化,天然线程安全
}
}
// 方式3:枚举(最简洁)
public enum Singleton {
INSTANCE;
public void doSomething() { }
}// 方式1:使用 Lock + Condition
class PrintABC {
private int state = 0;
private Lock lock = new ReentrantLock();
private Condition condA = lock.newCondition();
private Condition condB = lock.newCondition();
private Condition condC = lock.newCondition();
public void printA() {
lock.lock();
try {
while (state % 3 != 0) condA.await();
System.out.print("A");
state++;
condB.signal();
} finally { lock.unlock(); }
}
public void printB() {
lock.lock();
try {
while (state % 3 != 1) condB.await();
System.out.print("B");
state++;
condC.signal();
} finally { lock.unlock(); }
}
public void printC() {
lock.lock();
try {
while (state % 3 != 2) condC.await();
System.out.print("C");
state++;
condA.signal();
} finally { lock.unlock(); }
}
}
// 方式2:使用 Semaphore
Semaphore sa = new Semaphore(1);
Semaphore sb = new Semaphore(0);
Semaphore sc = new Semaphore(0);
// 线程A:sa.acquire() → print("A") → sb.release()
// 线程B:sb.acquire() → print("B") → sc.release()
// 线程C:sc.acquire() → print("C") → sa.release()// 方式1:BlockingQueue(推荐)
BlockingQueue queue = new LinkedBlockingQueue<>(1000);
// 生产者
executor.submit(() -> {
while (running) {
Task task = createTask();
queue.put(task); // 队列满时阻塞
}
});
// 消费者
executor.submit(() -> {
while (running) {
Task task = queue.take(); // 队列空时阻塞
process(task);
}
});
// 方式2:Disruptor(高性能)
// 无锁环形队列,适用于超高并发场景
// 设计要点:
// 1. 队列容量:根据生产/消费速度设置
// 2. 消费者数量:根据处理能力配置
// 3. 背压机制:队列满时的处理策略
// 4. 优雅关闭:处理完队列中的任务再关闭