java开发中进行并发编程时针对操做同一块区域时,若是不加锁会出现并发问题,数据不是本身预计获得的值。我以为有点像mysql事务中脏读、不可重复读、幻读的问题。加锁的目的是为了保证同一时间只有我一我的操做同一个资源。java
jdk提供给了咱们不少锁的实现方式,用于各类状况锁的使用:mysql
public class SynchronizedDemo {
public static void main(String[] args) {
Object o = new Object();
synchronized (o){
System.out.println("ReentrantLockDemo");
}
}
}
复制代码
ReentrantLock是怎么实现锁的机制呢? 经过继承AbstractQueuedLongSynchronizer(AQS)来进行锁的,实现原理是AQS中有一个变量来控制是否获取到了锁,经过Unsafe的CAS操做来获取锁,从而保证线程安全。sql
那么问题来了?CAS操做的ABA问题如何解决? concurrent包中有提供AtomicStampedReference来解决ABA问题,也就是在CAS操做的同时须要再增长版本的判断,从而保证不出现ABA的问题。编程
public class SolveCAS {
// 主内存共享变量,初始值为1,版本号为1
private static AtomicStampedReference<Integer> atomicStampedReference = new
AtomicStampedReference<>(1, 1);
public static void main(String[] args) {
// t1,指望将1改成10
new Thread(() -> {
// 第一次拿到的时间戳
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 第1次时间戳:"+stamp+" 值为:"+atomicStampedReference.getReference());
// 休眠5s,确保t2执行完ABA操做
try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
// t2将时间戳改成了3,cas失败
boolean b = atomicStampedReference.compareAndSet(1, 10, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+" CAS是否成功:"+b);
System.out.println(Thread.currentThread().getName()+" 当前最新时间戳:"+atomicStampedReference.getStamp()+" 最新值为:"+atomicStampedReference.getReference());
},"t1").start();
// t2进行ABA操做
new Thread(() -> {
// 第一次拿到的时间戳
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+" 第1次时间戳:"+stamp+" 值为:"+atomicStampedReference.getReference());
// 休眠,修改前确保t1也拿到一样的副本,初始值为1
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
// 将副本改成20,再写入,紧接着又改成1,写入,每次提高一个时间戳,中间t1没介入
atomicStampedReference.compareAndSet(1, 20, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+" 第2次时间戳:"+atomicStampedReference.getStamp()+" 值为:"+atomicStampedReference.getReference());
atomicStampedReference.compareAndSet(20, 1, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
System.out.println(Thread.currentThread().getName()+" 第3次时间戳:"+atomicStampedReference.getStamp()+" 值为:"+atomicStampedReference.getReference());
},"t2").start();
}
}
复制代码
使用场景不一样安全
ReadWriteLock可使用在读多写少的状况,尽可能提高并发的能力 ReadWriteLock、synchronized使用的是独占锁,可是jdk对synchronized在编译时会有优化。bash