美文网首页
谈谈synchronized、volatile、AtomicIn

谈谈synchronized、volatile、AtomicIn

作者: salix_ | 来源:发表于2020-02-03 16:51 被阅读0次

    内容

    Synchronized
    一:sychronized锁的是对象
    二:可重入
    三: 当synchronized遇到异常
    四:锁的是对象,不是那个引用变量名
    五:Synchronized得底层实现
    六:Synchronized的锁升级步骤
    volatile
    一:由问题引入Volatile,耐心看代码
    二:重排序问题
    AtomicInteger

    synchronized

    一:sychronized锁的是对象

    1:非静态方法,锁this对象

    下面两种情况都是一样的, 注意第二种synchronized锁的也是this对象,不是锁一个函数,也不是锁一段代码块。


    image.png
    image.png
    2:静态方法,锁class对象(反射机制)

    对于静态方法,就不能锁this对象了,因为即使你不new这个类的对象,也可以调用静态方法, 所以这个时候锁的是类的class对象(反射知识)


    image.png
    image.png

    二:可重入

    1:啥是可重入锁?

    https://www.cnblogs.com/incognitor/p/9894604.html

    2:情景一:一个线程的一个同步方法调用另一个同步方法
    image.png
    image.png
    3:情景二:一个线程的子类同步方法调用父类的同步方法,也是可重入的。(下面这段代码不会产生死锁)
    image.png

    三:当synchronized遇到异常:

    synchronized遇到异常之后,锁资源会释放,所以用synchronized锁的时候,一定要处理好异常。例:a线程对资源进行访问,修改了一半,出现了异常,锁释放。b线程继续访问,a线程没有回滚,也没有完成整个操作,可能会出问题。
    最好的方法就是try-catch处理异常,可以在catch里面回滚异常。

    四:锁的是对象,不是那个引用变量名,下面s1,s2是同一把锁。

    image.png

    五:Synchronized得底层实现

    汇编级别实现语句:lock cmpxchg
    cmpxchg操作系统级别得指令 本质就是和内存中得值 比较在修改
    lock就是加了一个锁
    硬件是锁一个北桥信号

    1. 每个对象new出来的时候,在jvm里的格局
    image.png
    2. synchronized其实主要是修改了对象头markword,通过修改对象头来实现偏向锁、自旋锁、重量级锁的转换。
    3.怎样修改呢?其实对象头是一个8位,32b大小的01串

    6.Synchronized的锁升级步骤

    首先是从申请到偏向锁,如果偏向锁不够了就升级到自旋锁。(竞争加剧,比如有线程超过10次自旋)这个时候就升级到重量级锁()

    volatile(使得变量在线程之间可见)

    一:

    1:下面这段代码居然会陷入死循环?在main这个线程里面讲running变成false居然没有改变创建线程的死循环!
    image.png
    2:加上一个volatile修饰running就可以了
    image.png
    3:为啥会这样?

    涉及到java的内存模型(JMM)
    贴一个链接https://www.jianshu.com/p/8a58d8335270
    可以去学习一下。
    大概意思就是JMM里有一个主内存,running这些个变量都存在于主内存。然而每一个线程都有一块自己的内存空间,创建线程A执行m()函数,会讲running变量拷贝一份到A的自己的内存空间。主线程(main)也会拷贝 一份running到自己的区域,设置running=false之后就把running写回主内存。但是A线程不会及时看主内存变了没有(并不是说不会主动更新主内存的变量到该线程内存区,比如下面图代码加个sleep就也可以正常结束。)所以导致了错误,具体的俺也不太清楚,应该是根据设置的算法有关系。而volaile的作用就是当变量改变的时候通知使用该变量的线程再刷新一下。

    image.png
    4:volatile只是保证了可见性,没有保证原子性。(就是不能代替synchronized)(据说面试会问到!!!

    因为volatile比synchronized更轻量级,所以能用volatile就不用synchronized。

    5:volatile和synchronized的区别:
    • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
    • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
    • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

    二:重排序问题(自己百度一下把)

    new一个没有加载进入内存的class的时候

    1. 首先会让其静态变量初始化(int 类型的就是0 对象默认就是null)
    2. 然后让静态变量赋值(static int count=3,那这一步就是count=3)
    3. 让变量指针指向这块内存(相当于这个变量指针不为空了)
      指针冲排序就是让2、3步骤反转。执行顺序是1、3、2。如果我们1、3执行完毕之后,这个时候指针默认不为空,会出现问题。可以看下面这篇文章,https://www.jianshu.com/p/840475e3c440

    AtomicInteger

    里面的操作可以保证原子性,incrementAndGet利用的就是CAS技术,相当于底层一条原子指令,这个过程中并没有上锁!只是用原子指令保证了线程安全。可以百度学习一下CAS。jdk1.8中ConcurrentHashMap内部利用的也是CAS技术(JDK1.7中ConcurrentHashMap利用的是分段锁)。实现用的是非常底层的技术,所以效率更高。
    举个例子,创建10个线程每个线程执行count++ 1000,最后能成功输出10000。避免了不可重复读问题。(count是AtomicInteger类型的)


    image.png

    相关文章

      网友评论

          本文标题:谈谈synchronized、volatile、AtomicIn

          本文链接:https://www.haomeiwen.com/subject/kxuhxhtx.html