【Java】【并发编程】Synchronized

在 Java 中,关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代Volatile功能)。

特点

  • 保证原子性:通过地城JVM实现,同一时间只有一个线程运行锁定代码块
  • 保证可见性,通过内存屏障(Load&store)实现,通过monitorenter加锁,monitorexit解锁,内部共享变量每次读取都强制从主内存读取最新值,释放锁后共享变量数据变更,强制刷新会主内存
  • 保证有序性:monitorenter加锁之后,同一时间只能被一个线程访问,即认为单线程执行,可以保证有序性,但无法禁止指令重排
  • 无法禁止指令重排:在代码块中,相当于单线程执行,单代码块的执行顺序可以指令重排
  • 通过Monitor管程监视器锁对象或ACC_SYNCHRONIZED修饰符实现加锁
    • monitorenter指令加锁,计数器+1
    • monitorexit指令释放锁,计数器-1
    • 线程解锁前,必须把共享变量的最新值刷新到主内存。
    • 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意,加锁与解锁是同一把锁)

实现(锁范围)

  • 修饰普通方法,当前对象锁
  • 修饰静态方法,类锁,所有类对象共用同一把锁
  • 修饰实例变量,仅对指定的对象加锁
   // 只能对不可变的共享对象加锁
   private final Object demo = new Demo();

   public synchronized void addNumber(long num){ // 对当前方法加锁,等同synchronized(this){}
      demo.count += num;
   }

   public static synchronized void addNumber_1(long num){ // 对类下所有对象加锁
      demo.count += num;
   }

   public void addNumber2(long num){
      synchronized (demo){ // 仅对demo加锁
         demo.count += num;
      }
   }

原理

  • 同步实例,使用monitor管程对象管理,monitorenter加锁和monitorexit释放锁
  • 同步方式,使用运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的
    • 静态方法还需要ACC_STATIC标志

修饰实例

    private final Demo DEMO = new Demo();
    public void test(){
        synchronized (DEMO){
            DEMO.test1(); // test1是Demo的普通方法,无需关注
        }
    }
  public void test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: getfield      #4                  // Field DEMO:Lcom/dongle/demo/jvm/lock/LockDemo$Demo;
         4: dup
         5: astore_1
         6: monitorenter
         7: aload_0
         8: getfield      #4                  // Field DEMO:Lcom/dongle/demo/jvm/lock/LockDemo$Demo;
        11: invokestatic  #5                  // Method com/dongle/demo/jvm/lock/LockDemo$Demo.access$100:(Lcom/dongle/demo/jvm/lock/LockDemo$Demo;)V
        14: aload_1
        15: monitorexit
        16: goto          24
        19: astore_2
        20: aload_1
        21: monitorexit
        22: aload_2
        23: athrow
        24: return
      Exception table:
         from    to  target type
             7    16    19   any
            19    22    19   any
      LineNumberTable:
        line 13: 0
        line 14: 7
        line 15: 14
        line 16: 24
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      25     0  this   Lcom/dongle/demo/jvm/lock/LockDemo;
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 19
          locals = [ class com/dongle/demo/jvm/lock/LockDemo, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 4
  1. 通过monitorenter加锁:6: monitorenter
  2. 通过monitorexit释放锁:15: monitorexit

修饰方法

    private final Demo DEMO = new Demo();
    public synchronized void test(){
        DEMO.test1(); // test1是Demo的普通方法,无需关注
    }
public synchronized void test();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #4                  // Field DEMO:Lcom/dongle/demo/jvm/lock/LockDemo$Demo;
         4: invokestatic  #5                  // Method com/dongle/demo/jvm/lock/LockDemo$Demo.access$100:(Lcom/dongle/demo/jvm/lock/LockDemo$Demo;)V
         7: return
      LineNumberTable:
        line 13: 0
        line 14: 7
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       8     0  this   Lcom/dongle/demo/jvm/lock/LockDemo;
  1. 通过方法修饰符ACC_SYNCHRONIZED隐式实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值