获课:666it.top/6121/
Java并发编程基石:线程生命周期与同步锁终极指南
一、线程生命周期详解
Java线程的生命周期是理解并发编程的基础,它由以下几个关键状态组成:
1. 线程状态全览
NEW(新建状态):通过new Thread()创建线程对象但尚未调用start()方法时的状态
RUNNABLE(可运行/运行状态):调用start()方法后进入的状态,包括就绪和运行中两种情况
BLOCKED(阻塞状态):线程试图获取对象锁而该锁被其他线程持有时的状态
WAITING(无限等待状态):线程等待其他线程执行特定操作(如Object.wait()或Thread.join())
TIMED_WAITING(定时等待状态):线程等待特定时间(如Thread.sleep(long))
TERMINATED(终止状态):线程执行完毕或异常退出的状态
2. 状态转换示例代码
Java
public class ThreadStateExample implements Runnable {
public static Thread thread1;
public static void main(String[] args) throws InterruptedException {
thread1 = new Thread(new ThreadStateExample());
System.out.println("State after creation: " + thread1.getState()); // NEW
thread1.start();
System.out.println("State after start: " + thread1.getState()); // RUNNABLE
Thread.sleep(100);
System.out.println("State while sleeping: " + thread1.getState()); // TIMED_WAITING
thread1.join();
System.out.println("State after completion: " + thread1.getState()); // TERMINATED
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
二、线程创建方式
Java提供了多种创建线程的方式:
1. 继承Thread类
Java
class MyThread extends Thread {
@Override
public void run() {
// 线程执行的代码
System.out.println("线程运行中...");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
2. 实现Runnable接口
Java
class MyRunnable implements Runnable {
@Override
public void run() {
// 线程执行的代码
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
三、同步锁机制详解
1. synchronized关键字
Java中最基本的同步机制,可用于方法和代码块:
Java
// 同步方法
public synchronized void synchronizedMethod() {
// 临界区代码
}
// 同步代码块
public void someMethod() {
synchronized(this) {
// 临界区代码
}
}
原理:synchronized会在进入代码块时自动加锁,退出时自动解锁。如果线程t1抢到了锁,其他线程将被阻塞,直到t1释放锁。
2. ReentrantLock
Java提供的更灵活的锁实现:
Java
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final ReentrantLock lock = new ReentrantLock();
private int count = 0;
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
特点:
可重入:同一线程可多次获取同一把锁
可中断:lockInterruptibly()方法允许在等待时响应中断
公平性:可选择公平或非公平锁
条件变量:支持多个条件队列
3. 读写锁(ReadWriteLock)
适用于读多写少的场景:
Java
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteCache {
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. StampedLock(Java8+)
提供乐观读锁机制,在读多写少场景下性能更优:
Java
import java.util.concurrent.locks.StampedLock;
public class Point {
private double x, y;
private final StampedLock sl = new StampedLock();
// 写锁示例
public void move(double deltaX, double deltaY) {
long stamp = sl.writeLock();
try {
x += deltaX;
y += deltaY;
} finally {
sl.unlockWrite(stamp);
}
}
// 乐观读示例
public double distanceFromOrigin() {
long stamp = sl.tryOptimisticRead();
double currentX = x, currentY = y;
if (!sl.validate(stamp)) {
stamp = sl.readLock();
try {
currentX = x;
currentY = y;
} finally {
sl.unlockRead(stamp);
}
}
return Math.sqrt(currentX * currentX + currentY * currentY);
}
}
四、高级同步工具
1. Semaphore(信号量)
控制同时访问特定资源的线程数量:
Java
import java.util.concurrent.Semaphore;
public class Pool {
private static final int MAX_AVAILABLE = 10;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// 实现细节省略...
}
2. CountDownLatch
允许一个或多个线程等待其他线程完成操作:
Java
import java.util.concurrent.CountDownLatch;
public class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // 返回
}
void doWork() { /* ... */ }
}
3. CyclicBarrier
让一组线程互相等待,直到所有线程都到达某个屏障点:
Java
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Solver {
final int N;
final float[][] data;
final CyclicBarrier barrier;
class Worker implements Runnable {
int myRow;
Worker(int row) { myRow = row; }
public void run() {
while (!done()) {
processRow(myRow);
try {
barrier.await();
} catch (InterruptedException | BrokenBarrierException ex) {
return;
}
}
}
}
public Solver(float[][] matrix) {
data = matrix;
N = matrix.length;
barrier = new CyclicBarrier(N,
() -> mergeRows(...));
// 创建并启动线程
}
}
五、死锁问题与预防
1. 死锁产生的四个必要条件
互斥条件:资源一次只能由一个线程占用
请求与保持条件:线程持有至少一个资源,并等待获取其他资源
不剥夺条件:已分配给线程的资源,不能被其他线程强行夺取
循环等待条件:存在一个线程等待的循环链
2. 死锁预防策略
避免嵌套锁:尽量不要在持有一个锁的同时去获取另一个锁
锁排序:确保所有线程以相同的顺序获取锁
锁超时:使用tryLock()设置超时时间
死锁检测:实现或使用现有的死锁检测机制
Java
// 使用tryLock避免死锁示例
public boolean transferMoney(Account from, Account to,
long amount, long timeout) {
long stopTime = System.nanoTime() + timeout;
while (true) {
if (from.lock.tryLock()) {
try {
if (to.lock.tryLock()) {
try {
if (from.getBalance() < amount)
throw new InsufficientFundsException();
from.debit(amount);
to.credit(amount);
return true;
} finally {
to.lock.unlock();
}
}
} finally {
from.lock.unlock();
}
}
if (System.nanoTime() > stopTime)
return false;
Thread.sleep(100);
}
}
六、性能优化建议
减少锁的粒度:尽量缩小同步代码块的范围
读写分离:读多写少时使用读写锁
避免锁的嵌套:减少死锁风险
考虑无锁编程:使用Atomic类等无锁数据结构
合理使用线程池:避免频繁创建销毁线程
通过深入理解线程生命周期和同步锁机制,开发者可以构建出高效、安全的并发Java应用程序。在实际开发中,应根据具体场景选择合适的同步策略,并始终注意线程安全和性能之间的平衡。
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传