zoukankan      html  css  js  c++  java
  • 深入理解synchronized

    加锁原理

      synchronized (a){} 锁住的就是()里面的对象,多个线程对同一个对象操作时,就会形成互斥效果,如果是操作两个不同的对象,那么就不会受synchronized影响。

    public class SynchronizedDemo {
        public static void main(String[] args) {
            SynchronizedDemo s = new SynchronizedDemo();
            Integer a = 1;
            Integer b = 2;
    
            new Thread(()->{
                s.sync(a);
            }).start();
            new Thread(()->{
                s.sync(b);
                //s.sync(a);
            }).start();
        }
    
        public void sync(Integer a){
            synchronized (a){
                System.out.println("线程:"+Thread.currentThread().getName()+" 获取到变量"+a);
                try {
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    在jdk中,synchronized同步是基于Monitor对象实现的,它里面主要有两个指令:
      monitorenter: 插入到同步代码块的开始位置
      monitorexit: 插入到同步代码块结束的位置
    它们对应着JMM模型8大原子操作的lock与unlock,lock获取锁后把对象加载到工作内存,数据操作完之后重新赋值到主内存,最后unlock解锁。JVM需要保证每一个monitorenter都有一个monitorexit与之对应。为了保证在方法异常时,monitorenter和monitorexit指令也能正常配对执行,编译器会自动产生一个异常处理器,它的目的就是用来执行 异常的monitorexit指令。通过monitor里的加锁计数器可以实现可重入的加锁。 Monitor(监视器锁)是依赖操作系统的Mutex Lock(互斥锁)实现的,需要向内核申请资源,此时cpu将由用户态转换为内核态,它是一个低性能重量级锁。

    synchronized优化

      jdk1.6之后就对这个synchronized锁进行了各种优化,是基于 jvm 通过 cas 设置头信息来做的。如适应性自旋锁、轻量级锁和偏向锁,并默认开启偏向锁。从 无锁—>偏向锁—>轻量级锁—>重量级锁 ,锁升级的这个过程是不可逆的。被加锁的对象 jvm中为它定义了一种对应的数据结构,通过判断数据结构的对象头就知道目前是什么锁状态。例如通过倒数第三个bit的值 0/1 就知道目前是无锁还是偏向锁了。

    三种锁的区别

      偏向锁:仅有一个线程进入临界区(主要用于不存在锁竞争,而是一个线程多次获得锁时,为的使线程获取锁使用最小的代价(因为只需要修改获取锁的线程id就好了))
      轻量级锁:多个线程交替进入临界区(当其他线程尝试竞争偏向锁时,会升级为轻量锁)
      重量级锁:多个线程同时进入临界区

    锁的升级过程

    1. 无锁:此时还没有线程获取所得资源

      

     2. 获取偏向锁:第一个线程获取到锁就会将前面的23个bit位修改为自己线程的id,将无锁升级为偏向锁。

       

     3. 升级轻量锁:此时另一个线程尝试获取锁,发现锁里的线程id并不是自己的,就会释放锁,将对象头重的Mark Word替换为指向锁记录的指针,将其升级为轻量锁。

      

    4. 若刚才将对象头重的Mark Word替换为指向锁记录的指针失败,则会自旋(循环等待)来获取锁,此时若有另一个线程同时竞争,锁会升级为重量级锁。

       

  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/wlwl/p/15004431.html
Copyright © 2011-2022 走看看