一、多线程基础概念
1. 进程与线程的区别
- 进程:操作系统资源分配的基本单位(拥有独立内存空间)
- 线程:CPU调度的基本单位(共享进程内存空间)
2. 线程的创建方式
方式1:继承Thread类
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("继承Thread方式运行,线程名:" + Thread.currentThread().getName());
}
}
// 启动方式
new MyThread().start(); // 必须调用start()而非run()
方式2:实现Runnable接口(推荐)
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("实现Runnable方式运行,线程名:" + Thread.currentThread().getName());
}
}
// 启动方式
new Thread(new MyRunnable()).start();
方式3:实现Callable接口(带返回值)
import java.util.concurrent.*;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Callable方式运行");
return 100;
}
}
// 启动方式
FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask).start();
Integer result = futureTask.get(); // 阻塞获取结果
3. 线程的生命周期
NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → TERMINATED
- NEW:新建状态
- RUNNABLE:就绪/运行状态
- BLOCKED:等待锁释放
- WAITING:调用Object.wait()等方法进入无限等待
- TIMED_WAITING:调用sleep()等方法进入有限时间等待
- TERMINATED:线程结束
二、线程同步机制
1. synchronized关键字
对象锁(实例方法)
public class Counter {
private int count = 0;
public synchronized void increment() { // 对象锁
count++;
}
}
类锁(静态方法)
public class StaticCounter {
private static int count = 0;
public static synchronized void increment() { // 类锁
count++;
}
}
同步代码块
public class BlockCounter {
private final Object lock = new Object();
private int count = 0;
public void increment() {
synchronized (lock) { // 指定锁对象
count++;
}
}
}
2. ReentrantLock可重入锁
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockDemo {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock(); // 获取锁
try {
count++;
} finally {
lock.unlock(); // 必须释放锁
}
}
}
3. 读写锁(ReadWriteLock)
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class Cache {
private final Map<String, Object> map = new HashMap<>();
private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
public Object get(String key) {
rwLock.readLock().lock();
try {
return map.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
map.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
三、线程通信机制
1. wait()/notify()方法
public class WaitNotifyDemo {
private static final Object lock = new Object();
private static boolean flag = false;
public static void main(String[] args) {
// 等待线程
new Thread(() -> {
synchronized (lock) {
while (!flag) {
try {
System.out.println("等待线程进入等待状态");
lock.wait(); // 释放锁并等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("等待线程被唤醒");
}
}).start();
// 通知线程
new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock) {
flag = true;
lock.notifyAll(); // 唤醒所有等待线程
System.out.println("通知线程发送通知");
}
}).start();
}
}
2. Condition对象(更灵活的线程通信)
import java.util.concurrent.locks.*;
public class ConditionDemo {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean flag = false;
public void await() throws InterruptedException {
lock.lock();
try {
while (!flag) {
System.out.println("等待线程进入等待状态");
condition.await(); // 必须配合lock使用
}
System.out.println("等待线程被唤醒");
} finally {
lock.unlock();
}
}
public void signal() throws InterruptedException {
lock.lock();
try {
flag = true;
condition.signalAll(); // 唤醒所有等待线程
System.out.println("通知线程发送通知");
} finally {
lock.unlock();
}
}
}
四、线程池技术
1. Executor框架核心类
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 创建线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 2. 提交任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.println("执行任务" + taskId + ",线程:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 3. 关闭线程池
executor.shutdown(); // 优雅关闭
// executor.shutdownNow(); // 立即关闭
}
}
2. ThreadPoolExecutor参数详解
// 核心线程数:5
// 最大线程数:10
// 空闲线程存活时间:60秒
// 任务队列:容量为100的LinkedBlockingQueue
// 线程工厂:自定义线程命名
// 拒绝策略:当队列满时直接抛出异常
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,
10,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
r -> new Thread(r, "custom-thread-" + r.hashCode()),
new ThreadPoolExecutor.AbortPolicy()
);
3. 常用拒绝策略
AbortPolicy:默认策略,直接抛出RejectedExecutionExceptionCallerRunsPolicy:由调用线程执行该任务DiscardPolicy:直接丢弃任务DiscardOldestPolicy:丢弃队列中最旧的任务
五、并发工具类
1. CountDownLatch(倒计时门闩)
import java.util.concurrent.*;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
CountDownLatch latch = new CountDownLatch(3); // 等待3个线程完成
for (int i = 0; i < 3; i++) {
final int workerId = i;
new Thread(() -> {
try {
Thread.sleep(1000 * (workerId + 1));
System.out.println("Worker " + workerId + " 完成工作");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
latch.countDown(); // 计数减1
}
}).start();
}
System.out.println("主线程等待所有Worker完成...");
latch.await(); // 阻塞直到计数为0
System.out.println("所有Worker完成,主线程继续执行");
}
}
2. CyclicBarrier(循环屏障)
import java.util.concurrent.*;
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有参与者到达屏障点,开始下一阶段");
});
for (int i = 0; i < 3; i++) {
final int riderId = i;
new Thread(() -> {
try {
System.out.println("骑手" + riderId + "准备就绪");
Thread.sleep(1000 * (riderId + 1));
System.out.println("骑手" + riderId + "到达屏障点");
barrier.await(); // 等待其他线程
System.out.println("骑手" + riderId + "继续比赛");
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
}
3. Semaphore(信号量)
import java.util.concurrent.*;
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问
for (int i = 0; i < 5; i++) {
final int carId = i;
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println("汽车" + carId + "进入停车场");
Thread.sleep(2000);
System.out.println("汽车" + carId + "离开停车场");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可
}
}).start();
}
}
}
六、原子类与并发集合
1. Atomic原子类
import java.util.concurrent.atomic.*;
public class AtomicDemo {
private static AtomicInteger atomicCount = new AtomicInteger(0);
private static int normalCount = 0;
public static void main(String[] args) throws InterruptedException {
// 原子类线程安全
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
atomicCount.incrementAndGet();
}
});
// 普通变量非线程安全
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
normalCount++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("AtomicInteger结果: " + atomicCount); // 20000
System.out.println("普通int结果: " + normalCount); // 可能是小于20000的随机值
}
}
2. 并发集合类
import java.util.concurrent.*;
public class ConcurrentCollectionDemo {
public static void main(String[] args) {
// ConcurrentHashMap
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("key1", "value1");
// CopyOnWriteArrayList(适合读多写少场景)
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item1");
// ConcurrentLinkedQueue
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("task1");
}
}
七、性能优化建议
-
合理设置线程池参数:
- CPU密集型任务:核心线程数 ≈ CPU核心数
- IO密集型任务:核心线程数 ≈ CPU核心数 * 2
-
避免锁的滥用:
- 尽量缩小同步代码块范围
- 优先使用不可变对象
- 考虑使用CAS(Compare-And-Swap)操作
-
使用并发工具替代wait/notify:
- 优先使用CountDownLatch/CyclicBarrier等工具类
-
合理使用volatile关键字:
- 保证可见性但不保证原子性
- 适用于状态标记等简单场景
八、总结
Java多线程编程是一个庞大而复杂的领域,本文系统梳理了:
- 线程创建与生命周期管理
- 同步机制(synchronized/Lock)
- 线程通信(wait/notify/Condition)
- 线程池技术(Executor框架)
- 并发工具类(CountDownLatch等)
- 原子类与并发集合
在实际开发中,应根据具体场景选择合适的并发控制手段,既要保证线程安全,又要避免过度同步导致的性能问题。建议通过JMH等工具进行性能测试,找到最优方案。
希望本文能为Java多线程学习者提供清晰的实践指南,后续将分享更多高并发场景的实战案例。