Synchronized升级过程是怎样的

技术Synchronized升级过程是怎样的Synchronized升级过程是怎样的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。要理解Synchron

什么是同步升级过程?针对这个问题,本文详细介绍了相应的分析和解决方法,希望能帮助更多想要解决这个问题的伙伴找到更简单易行的方法。

要理解Synchronized,首先要明确偏向锁、轻量锁和重量级锁。在使用方面,我们需要有等待/等待(时间)/通知/全部通知等。让我们介绍同步的过程和用法。

Synchronized的升级过程

(Java SE 1.6中为了减少获得锁和释放锁带来的 性能消耗而引入的偏向锁和轻量级锁)

Synchronized的升级顺序是 无锁--偏向锁--轻量级锁--重量级锁,顺内不可逆。

00-1010当一个线程访问同步代码块并获取锁时,会将锁偏置的线程ID存储在对象头和栈帧的锁记录中,偏置锁是可重入锁。未来在进入和退出同步代码块时,线程不需要CAS操作进行锁定和解锁,只需要简单的测试一下对象头的 Mark Word 里是否存储着指向当前线程的偏向锁(当前线程的线程ID).如果测试成功,则意味着线程已经获得了锁;如果测试失败,需要测试Mark Word中的偏置锁标志是否设置为1(表示当前是偏置锁);如果偏置锁标志为1,则使用 CAS 进行锁获取,和偏置锁标志不为1,则尝试使用CAS 将对象头的偏向锁指向当前线程和上述两个CAS来获取锁,如果CAS操作成功则获取到了偏向锁失败则代表出现了锁竞争,需要锁撤销操作.

00-1010部分锁使用等待竞争出现才释放锁,的机制,因此当其他线程试图争夺部分锁时,持有部分锁的线程将释放锁。部分锁的撤销需要一个等待拥有偏向锁的线程到达全局安全点(此时没有字节码被执行),它将首先暂停拥有偏向锁的线程,然后检查持有部分锁的线程是否是活动的。如果线程未激活,锁定对象的对象头将被设置为解锁状态。如果线程还活着,执行* *(判断是否需要持有锁),遍历偏向对象的锁记录,查看使用情况,如果还需要持有偏向锁,则偏向锁.带有偏置锁的Stacks会升级为轻量锁,如果不再需要偏置锁,锁对象会恢复到解锁状态,最终唤醒挂起的线程。

在00-1010线程执行同步块之前,JVM会先在当前线程的栈帧中创建一个存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称之为移置Mark Word。然后线程尝试使用CAS用指向锁定记录的指针替换对象头中的标记字。如果成功,当前线程获得锁;如果失败,这意味着其他线程争夺锁,当前线程试图使用自旋来获取锁,自旋有一定次数,如果超过设置自旋的次数则升级到重量级锁或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转.

偏向锁

轻度解锁时,将使用原子CAS操作将移位的标记字替换回对象头。如果成功了,就意味着没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁.

* *例如:*T1线程持有锁,T2线程旋转,但是T2线程的最大旋转次数已经过了,所以旋转失败,锁升级为重量级锁。T2线程被阻塞。此时,T1已经完成了同步代码块的执行,并解锁了轻量级锁。但是此时Mark Word中的标志位已经从00(偏置锁)变为10(中级锁),所以CAS解锁时会失败,T1会。

锁撤销

Synchronized是一个不公平的锁。当一个线程进入阻塞队列时,等待的线程会先尝试获取锁,如果无法获取,就会进入阻塞队列,这对已经进入队列的线程显然是不公平的。

轻量级锁

锁定优缺点偏向锁定的场景。

>加解锁不需要过多的资源消耗,和非同步方法的相比仅仅是纳秒的差距如果存在所竞争,会有额外的锁撤销操作适用于只有一个线程访问的场景轻量级锁竞争线程不会阻塞,会自旋,减少了上线文切换。如果始终得不到锁,会消耗cpu资源追求响应时间,同步代码块多为计算,执行快的场景重量级锁没啥优点线程阻塞响应时间慢同步代码块执行时间较长的场景使用

流程图

Synchronized升级过程是怎样的

  • Synchronized 方法

    1: Synchronized 是java的内置锁,也是排它锁非公平锁排它锁也就是当前线程获取锁后,其他线程都会阻塞挂起 ,非公平锁是在线程后去锁的时候会先尝试后去锁,获取不到在进行阻塞。

    2: Synchronized 是如何保证 '原子性' 的?是因为进入 Synchronized 块的内存语义是把 Synchronized 块内使用的 '工作内存清除', 这样在使用共享变量时就会直接存主内存中获取并复制到工作你内存中,在退出 Synchronized 语句块时 会把 工作内存中计算过的 '共享变量' 更新到主内存中。

    3: 获取到 Synchronized 锁 ,都是 '对象锁'而非'代码块锁' (锁的都是对象或类,而不是某个方法),因此 Synchronized 是具有可重入性,在获取到该对象锁后可以不用再次获取该对象其他方法的锁,直接进入。

    4: 如果是 Synchronized 用在 static 上, 就代表是类锁(.class)无论创建多少个对象都不可行

    区别

    wait和sleep区别在于wait会释放锁, 但是sleep不会释放锁 ,sleep会导致线程阻塞挂起。

    wait/wait(timeout)/notify/notifyAll 方法仅可以在获取到锁后才可以使用。

    解释

    wait: 线程等待。

    wait(time): 线程等待,如果时间超过了设置的time,则继续执行。

    notify: 随机唤醒一个等待的线程。

    notifyAll: 唤醒全部等待线程。

    代码演示

    /**
     * @Auther: concurrenncy
     * @Date: 2019-03-25 16:43
     * @Company: 随行付支付有限公司
     * @maill: lan_tao@suixingpay.com
     * @Description: wait 和 sleep 区别在于 wait会释放锁, 但是 sleep 不会 ,sleep会导致线程阻塞挂起
     */
            public class WaitAndNotifyTest {
                private static Object obj = new Object();
                public static void main(String[] args) {
                    // 创建线程 thread1
                    Thread thread1 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                System.out.println(Thread.currentThread().getName() + "   begin wait...");
                                synchronized (obj) {
                                    obj.wait();
                                }
                                System.out.println(Thread.currentThread().getName() + "   end wait...");
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }, "thread1");
                    // 创建线程 thread2
                    Thread thread2 = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                System.out.println(Thread.currentThread().getName() + "   begin wait...");
                                synchronized (obj) {
                                    obj.wait();
                                }
                                System.out.println(Thread.currentThread().getName() + "   end wait...");
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }, "thread2");
                    // 启动
                    thread1.start();
                    thread2.start();
                    try {
                        // 睡眠一秒
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 如果调用 notify 的线程未获取 对象锁,在调用 notify 的时候会抛出 java.lang.IllegalMonitorStateException 异常
                    synchronized (obj) {
                        // 唤醒 使用 obj 调用 wait 方法的其中一个线程 (随机)
                        obj.notify();
                        // 唤醒 使用呢 obj 调用 wait 方法的所有线程
                        obj.notifyAll();
                    }
                }
            }
  • 关于Synchronized升级过程是怎样的问题的解答就分享到这里了,希望

    内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/38063.html

    (0)

    相关推荐

    • Java中类和对象的示例分析

      技术Java中类和对象的示例分析这篇文章主要介绍了Java中类和对象的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。类可以看成是创建Java对象的

      攻略 2021年11月13日
    • 桑巴CVE-2018-1050和CVE-2018-1057指的是什么?

      技术Samba CVE-2018-1050和CVE-2018-1057指的是什么这篇文章将为大家详细讲解有关Samba CVE-2018-1050和CVE-2018-1057指的是什么,文章内容质量较高,因此小编分享给大

      攻略 2021年12月20日
    • 如何分析OpenLayers3加载矢量地图源的问题

      技术如何解析OpenLayers 3加载矢量地图源的问题今天就跟大家聊聊有关如何解析OpenLayers 3加载矢量地图源的问题,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可

      攻略 2021年12月23日
    • 简单平面图怎么画,ppt怎么做简单的平面图

      技术简单平面图怎么画,ppt怎么做简单的平面图1/7
      第一步:在PPT2010中,单击“插入”选项卡,在“插图”组中单击“形状”按钮,在弹出的下拉面板中选择“线条”中的“箭头”,在PPT编辑区按着shift键用鼠标横向拖

      生活 2021年10月30日
    • debug U命令中如何查看指定内存处内容翻译成的指令

      技术debug U命令中如何查看指定内存处内容翻译成的指令debug U命令中如何查看指定内存处内容翻译成的指令,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题

      攻略 2021年11月11日
    • 一斤是多少g,800克的东西是多少斤呢

      技术一斤是多少g,800克的东西是多少斤呢800克(g)=1.6斤。分析如下:500克等于1斤,300克等于300/500=0.6斤。所以800克等于1+0.6=1.6斤。千克是公制计量单位,一千克等于一公斤,合我国二市

      生活 2021年10月22日