JUC-Synchronized原理

110 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Synchronized基本概念

先了解几个术语:

  • 临界区: 指的是某⼀块代码区域块,它同⼀时刻只能由⼀个线程执⾏。
  • 竞态条件:对共享内存的进行竞争读写的地方
  • CAS(Compare and Swap ): 比较并交换,⽤于在硬件层⾯上提供原子性操作。 乐观锁就是用到了CAS

CAS

下面介绍CAS实现原子操作的两大问题

  • ABA问题:ABA问题就是⼀个值原来是A,变成了B,⼜变回了A。这个时候使⽤CAS是 检查不出变化的,但实际上却被更新了两次。 解决思路是使用“版本号”或者加上时间戳(JUC的atom包有响应的工具类可以使用)
  • 自旋开销大: CAS多与自旋结合。如果⾃旋CAS⻓时间不成功,会占⽤⼤量的CPU资源。 解决思路是让JVM⽀持处理器提供的pause指令, pause指令能让⾃旋失败时cpu睡眠⼀⼩段时间再继续自旋。

CAS+volatile实现无锁

class AccountSafe implements Account {
     private AtomicInteger balance; // 原子整数,用volatile实现的
     public AccountSafe(Integer balance) {
         this.balance = new AtomicInteger(balance);
     }
    
    
     @Override
     public Integer getBalance() {
         return balance.get();
     }
    
     @Override
     public void withdraw(Integer amount) {
         while (true) {
             int prev = balance.get();
             int next = prev - amount;
             if (balance.compareAndSet(prev, next)) { // cas
                 break;
             }
         }
     // 可以简化为下面的方法
     // balance.addAndGet(-1 * amount);
     }
}
  • CAS必须借助volatile才能读取到共享变量的最新值来实现【比较并交换】的效果

Synchronized使用

    // 关键字在实例⽅法上,锁为当前实例
    public synchronized void instanceLock() {
        // code
    }
    // 关键字在静态⽅法上,锁为当前Class对象
    public static synchronized void classLock() {
        // code
    }
    // 关键字在代码块上,锁为括号⾥⾯的对象
    public void blockLock() {
        Object o = new Object();
        synchronized (o) {
            // code
        }
    }

Synchronized实现原理

synchronized关键字的实现,依赖于Java的对象头中的Mark Word

Mark Word具体字段:

  • 默认存储对象的 HashCode、分代年龄、偏向模式以及锁标志位