Java线程同步主要通过以下几种机制实现,确保多线程环境下共享资源的安全访问:
1.synchronized关键字
原理:
-
基于JVM内置锁(监视器锁),通过修饰方法或代码块实现互斥访问。
-
线程进入同步代码前自动获取锁,退出时自动释放锁(包括异常退出)
-
提供互斥锁,确保同一时间只有一个线程访问同步代码块或方法。
// 同步实例方法:锁对象为当前实例。
public synchronized void syncMethod() {
// 临界区代码
}
// 同步代码块:显式指定锁对象(任意对象)
public void syncBlock() {
synchronized (lockObject) {
// 临界区代码
}
}
//同步静态方法:锁对象为类的Class对象。
public static synchronized void staticMethod() {
// 同步代码
}
-
特点:
-
隐式加锁/解锁,代码简洁。
-
JDK 1.6 后优化了锁机制(偏向锁、轻量级锁、重量级锁),性能提升显著。
-
不可中断,无法设置超时。
-
2. ReentrantLock(显式锁)
原理:
-
实现Lock接口,提供更灵活的锁控制(可重入、公平/非公平锁)。
-
需手动调用
lock()和unlock(),支持超时锁、可中断锁
private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock(); // 手动加锁
try {
// 临界区代码
} finally {
lock.unlock(); // 必须在finally中释放
}
}
// 尝试获取锁(超时机制)
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try { /* 操作 */ } finally { lock.unlock(); }
} else {
// 备选逻辑
}
适用场景:
-
需精细控制锁(如公平锁、超时锁)。
-
复杂同步逻辑(如多条件变量
Condition实现生产者-消费者模型)
-
特点:
-
支持可中断锁(lockInterruptibly())、超时锁(tryLock(timeout))、公平锁。
-
需手动加锁/解锁,避免死锁。
-
适合高竞争或复杂同步场景。
-
3. 原子变量(Atomic类)
原理:
-
基于CAS(Compare and Swap)操作,通过硬件指令保证原子性(无锁同步)。
-
适用于简单变量(如
AtomicInteger、AtomicReference)。
private AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet(); // 原子自增
}
适用场景:
-
高并发场景下的计数器、状态标志。
-
替代
synchronized提升性能(如累加操作) -
性能优于锁,但仅支持单一变量。
4. 线程安全的并发集合
原理:
-
内部实现线程安全机制,无需额外同步
-
例如:
-
ConcurrentHashMap:分段锁/CAS + 红黑树(JDK8+)。
-
CopyOnWriteArrayList:写时复制,适合读多写少。
-
BlockingQueue(如ArrayBlockingQueue):基于锁的阻塞队列
-
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("key", 1); // 线程安全操作
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("item"); // 写操作复制新数组
适用场景:
-
高并发数据存储(如缓存、任务队列)。
-
读多写少(
CopyOnWriteArrayList)或读写均衡(ConcurrentHashMap)
5. 其他同步工具
信号量(Semaphore)
-
控制资源访问的并发数(如数据库连接池)
Semaphore semaphore = new Semaphore(10); // 允许10个线程并发
semaphore.acquire(); // 获取许可
try { /* 操作 */ } finally { semaphore.release(); }
倒计时门闩(CountDownLatch)
-
等待多个线程完成后再执行主线程(如批量任务汇总)
CountDownLatch latch = new CountDownLatch(5);
// 子线程完成任务后调用 latch.countDown()
latch.await(); // 主线程等待所有任务完成
线程局部变量(ThreadLocal)
-
每个线程持有变量的独立副本,避免共享(如数据库连接)
private static ThreadLocal<Connection> connHolder = ThreadLocal.withInitial(() -> getConnection());
总结:如何选择同步方式?
| 同步方式 | 优势 | 适用场景 |
|---|---|---|
synchronized | 自动锁释放,语法简单 | 简单同步逻辑,低竞争场景 |
ReentrantLock | 支持超时、可中断锁,公平性可控 | 高竞争复杂逻辑(如死锁处理) |
| 原子变量 | 无锁操作,高性能 | 计数器、状态标志 |
| 并发集合 | 内置线程安全,无需额外同步 | 共享数据存储(缓存、队列) |
Semaphore/Latch | 控制并发数或协调多线程 | 资源池、批量任务调度 |
实践建议:
优先使用并发集合(如ConcurrentHashMap)减少手动同步;
简单操作选原子变量,复杂逻辑用
ReentrantLock;避免滥用
synchronized修饰整个方法,缩小同步范围
437

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



