
java多线程同步,线程安全--一网打尽
比较:读取共享变量的当前值(与期望值对比)。 交换:若当前值等于期望值,将变量更新为新值。 循环开销:失败时可能进入无限循环。 只能保证单个变量:对多个变量操作需额外措施。 ABA问题:版本化管理需谨慎处理。
发布日期:2021-05-10 04:59:20
浏览次数:25
分类:精选文章
本文共 2356 字,大约阅读时间需要 7 分钟。
Java线程同步技术详解
Java作为一款非常流行的程序语言,其线程同步机制至关重要。在多线程环境下,确保数据的安全性和可靠性是开发人员需要面对的最大挑战。以下是Java线程同步技术的全面解析,涵盖了Volatile、CAS、Synchronized、Lock等核心概念。
1. Volatile
Volatile是Java中用来解决多线程程序中可见性和有序性问题的关键字。其主要作用包括:
- 保证可见性:Volatile变量的值可以立即被所有线程读取。一旦某个线程修改了Volatile变量的值,其它线程就能立即获取最新值。
- 保证有序性:Volatile变量禁止指令优化,确保了线程内的操作在原样执行。常用于标记状态或双重检测机制。
Volatile实现原理
Volatile通过在不游程编译时插入内存屏障(如StoreStore、StoreLoad等),确保了在修改和读取时的原子性。这种机制防止了资源قام问题,确保多线程环境下的数据一致性。Volatile不能确保原子性,仅适用于状态标记和双重检测,需谨慎使用。
2. CAS(比较与交换)
CAS是一种乐观锁机制,基于乐观的假设,即通常情况下事务不会冲突。它通过以下步骤实现原子性操作:
JUC框架下AtomicInteger的实现
AtomicInteger类通过偏移地址和cas操作实现原子性,确保线程安全。其方法:get()
:返回当前值。set()
:直接修改值。compareAndSet(int expect, int update)
:基于CAS实现原子更新。
CAS的缺点
3. Synchronized
Synchronized是Java中的控制同步关键字,提供互斥锁机制。其特点:
- 锁机制:基于内存中的monitor对象,维护具有等待队列和退出拦截队列。
- 可重入性:允许同一线程多次获取同一锁,但需确保各次持有锁期间操作的一致性。
Synchronized的实现原理
Synchronized的加锁和解锁基于monitor的号召:在获取锁时增加计数器,在释放时减少计数器,实现互斥。优化包括自旋锁和锁消除等技术,提升性能。
4. Lock(Java 5新增的Lock接口)
Lock类提供了更灵活的锁机制,相较于synchronized具有以下优势:
- 可选释放:需手动释放锁,防止死锁。
- 可中断:支持用户中断等待锁的线程。
- 控制可重入:配合ReentrantLock实现可重入锁。
4.1 ReentrantLock(可重入锁)
ReentrantLock基于AbstractQueuedSynchronizer实现,可支持多级递归获取锁。其公平锁(FairSync)和非公平锁(NonfairSync)实现了不同的锁获取策略。
4.2 ReadWriteLock
ReadWriteLock允许多个线程共享读锁,但需独占写锁。其实现类ReentrantReadWriteLock支持多级锁获取,提升读操作的并发度。
5. ThreadLocal
ThreadLocal用于线程本地存储,在多线程环境下确保数据隔离。其基本用法:
public class ThreadLocalDemo { private static ThreadLocalthreadLocal = new ThreadLocal<>(); public static void main(String[] args) { Runnable task = () -> { try { for(int i=0; i<10; i++) { System.out.println(Thread.currentThread().getName() + ": " + threadLocal.get()); threadLocal.set("Hello, " + i); } } catch(InvalidStateException e) { System.out.println(Thread.currentThread().getName() + ": 无法设置ThreadLocal值"); } }; for(int i=0; i<10; i++) { String threadName = "Thread-" + i; Thread t = new Thread(task, threadName); t.start(); } try { Thread.sleep(100); System.out.println("主线程结束"); } catch(InterruptedException e) { e.printStackTrace(); } }}
每个线程具有独立的ThreadLocal值,防止线程间数据干扰,常用于缓存和持久化存储。