一、多线程基础概念
1.1 进程与线程的区别
进程是操作系统资源分配的基本单位,具有独立的内存空间和系统资源。线程是CPU调度的基本单位,是进程中的一个执行路径,共享进程的内存和资源。
主要区别:
-
进程间相互独立,线程共享进程资源
-
进程切换开销大,线程切换开销小
-
进程通信复杂(IPC),线程通信简单(共享内存)
-
进程更安全(隔离),线程更高效
1.2 为什么需要多线程
-
提高CPU利用率:当线程因I/O操作阻塞时,其他线程可以继续执行
-
提高响应性:GUI应用使用多线程保持界面响应
-
简化建模:某些问题(如仿真)更适合用多线程表达
-
充分利用多核CPU:现代CPU多为多核,多线程可以并行执行
1.3 Java线程实现方式
1.3.1 继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread running: " + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
1.3.2 实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable running: " + Thread.currentThread().getName());
}
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
1.3.3 实现Callable接口(带返回值)
class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
return "Callable result: " + Thread.currentThread().getName();
}
}
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get()); // 获取返回值
}
1.3.4 Lambda表达式(Java8+)
public static void main(String[] args) {
// Runnable
new Thread(() -> System.out.println("Lambda thread running")).start();
// Callable
FutureTask<String> futureTask = new FutureTask<>(() -> "Lambda callable");
new Thread(futureTask).start();
}
二、线程生命周期与状态转换
2.1 线程的6种状态(Java Thread.State)
-
NEW:新建但未启动
-
RUNNABLE:可运行(包括就绪和运行中)
-
BLOCKED:等待监视器锁(synchronized)
-
WAITING:无限期等待(wait()/join()/park())
-
TIMED_WAITING:有限期等待(sleep()/wait(n)/join(n))
-
TERMINATED:终止
2.2 状态转换图
NEW --start()--> RUNNABLE RUNNABLE --获取锁--> 运行中 RUNNABLE --未获取锁--> BLOCKED RUNNABLE --wait()/join()--> WAITING RUNNABLE --sleep(n)/wait(n)/join(n)--> TIMED_WAITING WAITING/TIMED_WAITING --notify()/notifyAll()/unpark()/超时--> RUNNABLE 任何状态 --异常/完成--> TERMINATED
2.3 状态检查与控制方法
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(thread.getState()); // NEW
thread.start();
System.out.println(thread.getState()); // RUNNABLE
Thread.sleep(100);
System.out.println(thread.getState()); // TIMED_WAITING
thread.join();
System.out.println(thread.getState()); // TERMINATED
三、线程同步与锁机制
3.1 同步问题示例:银行转账
j
class BankAccount {
private int balance;
public BankAccount(int balance) {
this.balance = balance;
}
// 非同步方法会导致并发问题
public void transfer(BankAccount dest, int amount) {
this.balance -= amount;
dest.balance += amount;
}
}
3.2 synchronized关键字
3.2.1 同步方法
public synchronized void transfer(BankAccount dest, int amount) {
this.balance -= amount;
dest.balance += amount;
}
3.2.2 同步代码块
public void transfer(BankAccount dest, int amount) {
synchronized(this) {
this.balance -= amount;
synchronized(dest) {
dest.balance += amount;
}
}
}
3.3 volatile关键字
保证变量的可见性(但不保证原子性):
class SharedObject {
private volatile boolean flag = false;
public void setFlag() {
flag = true;
}
public void doWork() {
while(!flag) {
// 循环直到flag变为true
}
}
}
3.4 Java并发包中的锁
3.4.1 ReentrantLock
class Counter {
private final Lock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
3.4.2 ReadWriteLock
class DataCache {
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private Map<String, Object> cache = new HashMap<>();
public Object get(String key) {
rwLock.readLock().lock();
try {
return cache.get(key);
} finally {
rwLock.readLock().unlock();
}
}
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
cache.put(key, value);
} finally {
rwLock.writeLock().unlock();
}
}
}
四、线程间通信
4.1 wait()/notify()机制
class MessageQueue {
private Queue<String> queue = new LinkedList<>();
private int maxSize;
public MessageQueue(int maxSize) {
this.maxSize = maxSize;
}
public synchronized void put(String message) throws InterruptedException {
while(queue.size() == maxSize) {
wait(); // 队列满时等待
}
queue.add(message);
notifyAll(); // 通知消费者
}
public synchronized String take() throws InterruptedException {
while(queue.isEmpty()) {
wait(); // 队列空时等待
}
String message = queue.remove();
notifyAll(); // 通知生产者
return message;
}
}
4.2 Condition条件变量
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while(count == items.length)
notFull.await();
items[putptr] = x;
if(++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while(count == 0)
notEmpty.await();
Object x = items[takeptr];
if(++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
五、Java并发工具类
5.1 CountDownLatch
public class WorkerService {
public static void main(String[] args) throws InterruptedException {
int workerCount = 5;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(workerCount);
for(int i = 0; i < workerCount; i++) {
new Thread(new Worker(startSignal, doneSignal, "Worker-"+i)).start();
}
System.out.println("准备工作...");
Thread.sleep(1000); // 模拟准备工作
System.out.println("开始工作!");
startSignal.countDown(); // 所有worker开始工作
doneSignal.await(); // 等待所有worker完成
System.out.println("所有工作完成!");
}
static class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final String name;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal, String name) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.name = name;
}
public void run() {
try {
startSignal.await(); // 等待开始信号
System.out.println(name + " 正在工作...");
Thread.sleep((long)(Math.random() * 1000)); // 模拟工作
System.out.println(name + " 工作完成");
doneSignal.countDown();
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
}
5.2 CyclicBarrier
public class MeetingPoint {
public static void main(String[] args) {
int threadCount = 3;
CyclicBarrier barrier = new CyclicBarrier(threadCount, () ->
System.out.println("所有线程已到达屏障点,继续执行"));
for(int i = 0; i < threadCount; i++) {
new Thread(new Task(barrier), "Thread-"+i).start();
}
}
static class Task implements Runnable {
private final CyclicBarrier barrier;
Task(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " 开始第一阶段工作");
Thread.sleep((long)(Math.random() * 2000));
System.out.println(Thread.currentThread().getName() + " 到达屏障点");
barrier.await();
System.out.println(Thread.currentThread().getName() + " 开始第二阶段工作");
Thread.sleep((long)(Math.random() * 2000));
System.out.println(Thread.currentThread().getName() + " 到达屏障点");
barrier.await();
System.out.println(Thread.currentThread().getName() + " 完成所有工作");
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
5.3 Semaphore
public class ConnectionPool {
private static final int MAX_AVAILABLE = 10;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
private final Set<Connection> connections = new HashSet<>();
public ConnectionPool() {
for(int i = 0; i < MAX_AVAILABLE; i++) {
connections.add(new MockConnection());
}
}
public Connection getConnection() throws InterruptedException {
available.acquire();
return getNextAvailableConnection();
}
public void releaseConnection(Connection c) {
if(markAsUnused(c)) {
available.release();
}
}
private synchronized Connection getNextAvailableConnection() {
for(Connection c : connections) {
if(!c.isInUse()) {
c.markInUse();
return c;
}
}
return null;
}
private synchronized boolean markAsUnused(Connection c) {
if(c.isInUse()) {
c.markUnused();
return true;
}
return false;
}
interface Connection {
void markInUse();
void markUnused();
boolean isInUse();
}
class MockConnection implements Connection {
private volatile boolean inUse = false;
public void markInUse() { inUse = true; }
public void markUnused() { inUse = false; }
public boolean isInUse() { return inUse; }
}
}
六、线程池与Executor框架
6.1 线程池的优势
-
降低资源消耗:重复利用已创建的线程
-
提高响应速度:任务到达时线程已存在
-
提高线程可管理性:统一分配、调优和监控
-
提供更多功能:定时执行、定期执行等
6.2 ThreadPoolExecutor
public class ThreadPoolDemo {
public static void main(String[] args) {
int corePoolSize = 5;
int maxPoolSize = 10;
long keepAliveTime = 5000;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
corePoolSize, // 核心线程数
maxPoolSize, // 最大线程数
keepAliveTime, // 空闲线程存活时间
TimeUnit.MILLISECONDS, // 时间单位
new LinkedBlockingQueue<Runnable>(100), // 工作队列
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
for(int i = 0; i < 20; i++) {
executor.execute(new Task("Task-"+i));
}
executor.shutdown();
}
static class Task implements Runnable {
private final String name;
Task(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " 执行 " + name);
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
6.3 Executors工厂类
// 固定大小线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
// 单线程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 可缓存线程池
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 定时任务线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
// 工作窃取线程池(Java8+)
ExecutorService workStealingPool = Executors.newWorkStealingPool();
6.4 Fork/Join框架
public class FibonacciTask extends RecursiveTask<Long> {
private final long n;
FibonacciTask(long n) {
this.n = n;
}
@Override
protected Long compute() {
if(n <= 1) {
return n;
}
FibonacciTask f1 = new FibonacciTask(n - 1);
f1.fork(); // 异步执行
FibonacciTask f2 = new FibonacciTask(n - 2);
return f2.compute() + f1.join(); // 等待结果
}
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
FibonacciTask task = new FibonacciTask(10);
System.out.println(pool.invoke(task)); // 输出55
}
}
七、并发集合与原子类
7.1 并发集合类
7.1.1 ConcurrentHashMap
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("a", 1);
map.putIfAbsent("a", 2); // 不会替换已有值
// 原子更新
map.compute("a", (k, v) -> v == null ? 1 : v + 1);
// 搜索
Integer result = map.search(1, (k, v) -> v > 0 ? k : null);
7.1.2 CopyOnWriteArrayList
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("a");
list.addIfAbsent("a"); // 不会添加重复元素
// 迭代期间安全修改
for(String s : list) {
list.add("new"); // 不会抛出ConcurrentModificationException
}
7.2 阻塞队列
7.2.1 ArrayBlockingQueue
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
queue.put("item"); // 阻塞直到有空间
String item = queue.take(); // 阻塞直到有元素
7.2.2 LinkedBlockingQueue
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
queue.offer("item", 1, TimeUnit.SECONDS); // 限时等待
String item = queue.poll(1, TimeUnit.SECONDS);
7.3 原子类
7.3.1 AtomicInteger
AtomicInteger counter = new AtomicInteger(0); counter.incrementAndGet(); // 原子自增 counter.compareAndSet(1, 2); // CAS操作
7.3.2 LongAdder(高并发场景更优)
LongAdder adder = new LongAdder(); adder.increment(); adder.add(5); long sum = adder.sum(); // 获取总和
八、Java内存模型与线程安全
8.1 Java内存模型(JMM)
-
主内存:所有变量存储的位置
-
工作内存:每个线程有自己的工作内存,保存主内存变量的副本
-
内存间交互操作:
-
lock(锁定)
-
unlock(解锁)
-
read(读取)
-
load(载入)
-
use(使用)
-
assign(赋值)
-
store(存储)
-
write(写入)
-
8.2 happens-before原则
-
程序顺序规则:同一线程中的操作,前面的happens-before后面的
-
监视器锁规则:解锁happens-before后续加锁
-
volatile变量规则:写happens-before后续读
-
线程启动规则:start()happens-before线程中的任何操作
-
线程终止规则:线程中的所有操作happens-before它的终止检测
-
中断规则:对线程interrupt()的调用happens-before被中断线程的代码检测到中断
-
终结器规则:对象的构造函数happens-before它的finalize()方法
-
传递性:A happens-before B,B happens-before C,则A happens-before C
8.3 线程安全实现方法
-
不可变对象:String、Integer等
-
互斥同步:synchronized、ReentrantLock
-
非阻塞同步:CAS操作(Atomic类)
-
无同步方案:ThreadLocal、栈封闭
九、常见多线程问题与解决方案
9.1 死锁与避免
死锁示例:
Object lock1 = new Object();
Object lock2 = new Object();
new Thread(() -> {
synchronized(lock1) {
try { Thread.sleep(100); } catch(Exception e) {}
synchronized(lock2) {
System.out.println("Thread1 got both locks");
}
}
}).start();
new Thread(() -> {
synchronized(lock2) {
try { Thread.sleep(100); } catch(Exception e) {}
synchronized(lock1) {
System.out.println("Thread2 got both locks");
}
}
}).start();
避免死锁策略:
-
按固定顺序获取锁
-
使用tryLock()设置超时
-
使用死锁检测工具
9.2 线程泄漏
原因:
-
线程未正确关闭
-
线程池未正确shutdown
解决方案:
ExecutorService executor = Executors.newFixedThreadPool(5);
try {
// 提交任务
executor.submit(() -> {...});
} finally {
executor.shutdown(); // 或shutdownNow()
if(!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
}
9.3 上下文切换开销
优化建议:
-
减少锁竞争(缩小同步范围、使用读写锁)
-
使用无锁数据结构(ConcurrentHashMap、Atomic类)
-
合理设置线程池大小(CPU密集型:CPU核数+1;IO密集型:2*CPU核数)
十、Java多线程最佳实践
-
命名线程:方便调试和日志追踪
java
复制
下载
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder() .setNameFormat("worker-%d").build(); ExecutorService executor = Executors.newFixedThreadPool(5, namedThreadFactory); -
优先使用并发工具类:而不是自己实现同步机制
-
处理中断:正确响应中断
public void run() { try { while(!Thread.currentThread().isInterrupted()) { // 工作代码 } } catch(InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } } -
避免过度同步:缩小同步范围,使用并发集合
-
使用ThreadLocal谨慎:防止内存泄漏
try { ThreadLocal<Object> threadLocal = new ThreadLocal<>(); threadLocal.set(new Object()); // 使用threadLocal } finally { threadLocal.remove(); // 必须清理 } -
考虑使用CompletableFuture(Java8+):
CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") .thenAccept(System.out::println);
总结
Java多线程编程是Java开发中的核心技能,掌握多线程技术可以:
-
提高程序性能
-
改善用户体验
-
更好地利用硬件资源
但同时也带来复杂性:
-
线程安全问题
-
死锁风险
-
性能调优挑战
建议开发者在实际项目中:
-
优先使用高级并发工具(如线程池、并发集合)
-
编写线程安全的代码
-
进行充分的并发测试
-
使用性能分析工具(如JProfiler、VisualVM)调优
随着Java版本更新,多线程API也在不断改进(如Java8的CompletableFuture、Java9的Flow API等),开发者应持续学习新的并发编程模式和技术。

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



