高并发的解决方案
volatile、synchronized、Lock、AtomicInteger
Volatile
volatile是一种稍弱的同步机制,在访问volatile变量时不会执行加锁操作,也就不会执行线程阻塞。他实现的是变量的可见性与一致性,但是他的原子性是保证不了。读取Volatile可以使用Unsafe.getObjectVolatile()获取,保证一致性。
synchronized(悲观锁)
锁的对象
public synchronized void method()
synchronized(this)
//零长度的byte数组对象创建起来将比任何对象都经济
byte[] lock = new byte[0]
synchronized(lock)
public synchronized static void method()
synchronized(Foo.class)
Foo.class和 P1.getClass()用于作同步锁还不相同
Lock(独占锁)
分析一下synchronized(隐式锁)的缺点:
1、占有synchronized锁的线程只有执行完该代码块,才能释放对锁的占有;
2、其他线程尝试获取synchronized锁,会一直尝试,无法知道结果,无法中断;
3、读写操作的时候,读与读之间不会互斥,synchronized锁无法实现;
Lock的Api:
// 获取锁
void lock()
// 如果当前线程未被中断,则获取锁,可以响应中断 ,方法外声明抛出 InterruptedException
void lockInterruptibly()
// 返回绑定到此 Lock 实例的新 Condition 实例
Condition newCondition()
// 仅在调用时锁为空闲状态才获取该锁,可以响应中断
boolean tryLock()
// 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁
boolean tryLock(long time, TimeUnit unit)
// 释放锁
void unlock()
ReadWriteLock(共享锁)
//返回用于读取操作的锁 共享锁
Lock readLock()
//返回用于写入操作的锁 独占锁
Lock writeLock()
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持,而写入锁是独占的。
AtomicInteger(乐观锁+自旋锁)
乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。
我们可以看出AtomicInteger各属性的作用:
unsafe: 获取并操作内存的数据。
valueOffset: 存储value在AtomicInteger中的偏移量。
value: 存储AtomicInteger的int值,该属性需要借助volatile关键字保证其在线程间是可见的。
incrementAndGet()
getAndAddInt()循环获取给定对象o中的偏移量处的值v,然后判断内存值是否等于v。如果相等则将内存值设置为 v + delta,否则返回false,继续循环进行重试,直到设置成功才能退出循环,并且将旧值返回。整个“比较+更新”操作封装在compareAndSwapInt()中,在JNI里是借助于一个CPU指令完成的,属于原子操作,可以保证多个线程都能够看到同一个变量的修改值。
CAS算法涉及到三个操作数:
需要读写的内存值 V。进行比较的值 A。要写入的新值 B。
CAS的问题:1. ABA问题。2. 循环时间长开销大。3. 只能保证一个共享变量的原子操作。