属于悲观锁,有共享资源,需要加锁时,会以独占锁的方式导致其它需要获取锁才能执行的线程挂起,等待持有锁的钱程释放锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁的思想。
多线程并发修改一个值时的实现:
public class SimulatedCAS {
//加volatile的目的是利用其happens-before原则,保证线程可见性
private volatile int value;
public synchronized int getValue() { return value; }
public synchronized int compareAndSwap(int expectedValue, int newValue) {
int oldValue = value;
if (value == expectedValue)
value = newValue;
return oldValue;
}
}
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。 在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。乐观锁一般会使用版本号机制或CAS算法实现。
public class CasCounter {
private SimulatedCAS value;
public int getValue() {
return value.getValue();
}
public int increment() {
int oldValue = value.getValue();
while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
oldValue = value.getValue();
return oldValue + 1;
}
}
JDK5.0之后加入了java.util.concurrent.atomic 包,其中的AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean 等都是在CAS基础上实现的。
public class AtomicTest {
private static AtomicInteger atomicInteger = new AtomicInteger(100);
private static AtomicStampedReference<Integer> atomicStampedReference =
new AtomicStampedReference<Integer>(99, 0);
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
atomicInteger.compareAndSet(99, 100);
atomicInteger.compareAndSet(100, 99);
});
Thread thread2 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
boolean b = atomicInteger.compareAndSet(99, 100);
System.out.println(b);
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
Thread refT1 = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(99, 100,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
atomicStampedReference.compareAndSet(100, 99,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
});
Thread refT2 = new Thread(() -> {
int stamp = atomicStampedReference.getStamp();
System.out.println("before sleep : stamp = " + stamp); // stamp = 0
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after sleep : stamp = " + atomicStampedReference.getStamp());//stamp = 1
boolean c3 = atomicStampedReference.compareAndSet(99, 100, stamp, stamp+1);
System.out.println(c3); //false
});
refT1.start();
refT2.start();
}
}
结果如下:
true
before sleep : stamp = 0
after sleep : stamp = 2
false
也就是说AtomicInteger更新成功,而AtomicStampedReference更新失败。