Java三种不同的锁
程序员文章站
2022-05-04 15:53:10
...
-
Java中,锁分为乐观锁和悲观锁两类(数据库乐观锁和悲观锁参考 http://blog.csdn.net/liupeng_qwert/article/details/72935469)
悲观锁:直接将在并发情况下可能出问题的代码加同步,同一时刻只允许一个线程访问,典型的代表是synchronized
乐观锁:每次不加锁去执行某项操作,如果发生冲突则失败并重试,直到成功为止,也称之为【自旋】
乐观锁实现利用了CAS机制(Compare and Swap),CAS则依赖于CPU特殊指令实现 什么是CAS
2.1 原理:“CAS有三个操作数,内存数据v,旧的预期数据A,要修改的数据B。每次进行数据更新时,当且仅当预期值A和内存中的数据V相同时,才将内存中的数据修改为B,否则什么也不做”
2.2 哪些Java类实现利用了乐观锁(CAS)
Java中的原子类利用了CPU的CAS机制,例如AtomicInteger、AtomicBoolean、AtomicLong、AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray,以AtomicInteger为例,查看源码实现
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
/**
* Atomically sets the value to the given updated value
* if the current value {@code ==} the expected value.
*
* @param expect the expected value
* @param update the new value
* @return true if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
2.3 CAS可能出现ABA问题?
3 基于synchronized实现锁
(1) 基于JVM实现,synchronized锁即对象监视器,属于独占锁
(2) JDK1.5之前只能通过synchronized实现同步
(3) 同步代码实际上是单线程访问,效率比较低,因此同步块(block)越小越好
//例如单例模式实现中的双重校验
public class JDBCSingleton4 {
/**
* 构造函数私有,避免类在外部被实例化
*/
private JDBCSingleton4(){
}
private static JDBCSingleton4 jdbcSingleton = null; // 懒汉模式3,双中检查锁定,线程安全
public static JDBCSingleton4 getJDBCSinleton(){ // synchronized关键字不加在方法上,避免每次都要同步,显著提升性能
if(jdbcSingleton == null){
synchronized(JDBCSingleton4.class){
if(jdbcSingleton == null){
jdbcSingleton = new JDBCSingleton4();
}
}
}
return jdbcSingleton;
}
}
(4) 内部原理示意图
4 基于lock实现锁
public class LockMethod {
public static void main(String[] args) {
final Table6 tObj = new Table6(); // 共享对象
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
tObj.print(5);
}
});
Thread t2 = new Thread(new Runnable(){
@Override
public void run(){
tObj.print(100);
}
});
t1.start();
t2.start();
}
}
class Table6 {
private Lock lock = new ReentrantLock();
public void print(int n){
try {
lock.lock();
for(int i=1; i<= 5; i++){
System.out.println(n*i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
lock.unlock();
}
}
}
输出结果
5
10
15
20
25
100
200
300
400
500
可以看出,没有出现线程交叉访问的情况,线程安全
5 基于CAS实现锁