您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    面试题:再谈Synchronized完成原理!
    时间:2021-08-06 21:12 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    面试题:再谈Synchronized完成原理!

    前言

    线程安全是并发编程中的重要关注点。

    形成线程安全成绩的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据。

    为了处置这个成绩,我们能够需求这样一个方案,当存在多个线程操作共享数据时,需求保证同一时辰有且只要一个线程在操作共享数据,其他线程必须等到该线程处置完数据后再停止。

    在 Java 中,关键字 Synchronized可以保证在同一个时辰,只要一个线程可以执行某个办法或许某个代码块(主要是对办法或许代码块中存在共享数据的操作)。

    下面来一同探求Synchronized的基本运用、完成机制。

    面试题来自:社招一年半面经分享(含阿里美团头条京东滴滴)

    用法 两类锁:

    对象锁:包括办法锁(默许锁对象为this以后实例对象)和同步代码块锁(本人指定锁对象)。

    类锁:指Synchronized修饰静态的办法或指定锁为Class对象。

    当一个线程试图拜访同步代码块时,它首先必须失掉锁,而参加或抛出异常时必须释放锁。

    给普通办法加锁时,上锁的对象是 this;

    给静态办法加锁时,锁的是 class 对象;

    给代码块加锁,可以指定一个详细的对象作为锁。

    代码示例如下:

    public class SynchronizedTest { 

     

        /** 

         * 修饰静态办法, 同等于下面注释的办法 

         */ 

        public synchronized static void test1() { 

            System.out.println("月伴飞鱼"); 

        } 

     

     

    //    public static void test1() { 

    //        synchronized (SynchronizedTest.class){ 

    //            System.out.println("月伴飞鱼"); 

    //        } 

    //    } 

     

     

        /** 

         * 修饰实例办法, 同等于下面注释的办法 

         */ 

        public synchronized void test2(){ 

            System.out.println("月伴飞鱼"); 

        } 

     

    //    public void test2(){ 

    //        synchronized (this){ 

    //            System.out.println("月伴飞鱼"); 

    //        } 

    //    } 

     

        /** 

         * 修饰代码块 

         */ 

        public void test3(){ 

            synchronized (this){ 

                System.out.println("月伴飞鱼"); 

            } 

        } 

     

    多线程拜访同步办法的几种状况:

    两个线程同时拜访一个对象的同步办法。

    由于同步办法锁运用的是this对象锁,同一个对象的this锁只要一把,两个线程同一时间只能有一个线程持有该锁,所以该办法将会串行运转。

    两个线程拜访的是两个对象的同步办法。

    由于两个对象的this锁互不影响,Synchronized将不会起作用,所以该办法将会并行运转。

    两个线程拜访的是Synchronized的静态办法。

    Synchronized修饰的静态办法获取的是以后类模板对象的锁,该锁只要一把,无论拜访多少个该类对象的办法,都将串行执行。

    同时拜访同步办法与非同步办法

    非同步办法不受影响。

    拜访同一个对象的不同的普通同步办法。

    由于this对象锁只要一个,不同线程拜访多个普通同步办法将串行运转。

    同时拜访静态Synchronized和非静态Synchronized办法

    静态Synchronized办法的锁为class对象的锁,非静态Synchronized办法锁为this的锁,它们不是同一个锁,所以它们将并行运转。

    运用优化

    大家在运用synchronized关键字的时分,能够常常会这么写:

    synchronized (this) { 

      ... 

    它的作用域是以后对象,锁的就是以后对象,谁拿到这个锁谁就可以运转它所控制的代码。

    当有一个明白的对象作为锁时,就可以这么写,但是当没有一个明白的对象作为锁,只想让一段代码同步时,可以创立一个特殊的变量(对象)来充任锁:

    public class Demo { 

        private final Object lock = new Object(); 

     

        public void methonA() { 

          synchronized (lock) { 

            ... 

          } 

        } 

    这样写没成绩。但是用new Object()作为锁对象能否是一个最佳选择呢?

    我在StackOverFlow看到这么一篇文章:object-vs-byte0-as-lock

    大意就是用new byte[0]作为锁对象更好,会增加字节码操作的次数。

    public class Demo { 

        private final byte[] lock = new byte[0]; 

    详细细节大家,可以看看这篇文章,算提供一种思绪吧!

    完成原理

    由于Synchronized锁的是对象,在解说原理之前先引见下对象结构相关知识。

    HotSpot虚拟机中,对象在内存中存储的规划可以分为三块区域:对象头、实例数据和对齐填充。

    对象头

    对象头包括两部分信息:运转时数据Mark Word和类型指针

    假设对象是数组对象,那么对象头占用3个字宽(Word)(需求记载数组长度),假设对象是非数组对象,那么对象头占用2个字宽(1word = 2Byte = 16bit)

    对象头的类型指针指向该对象的类元数据,虚拟机经过这个指针可以确定该对象是哪个类的实例

    Mark Word

    用于存储对象本身的运转时数据, 如哈希码(HashCode)、GC分代年龄、锁形状标志、线程持有的锁、倾向线程ID、倾向时间戳等等,它是完成轻量级锁和倾向锁的关键。

    这部分数据的长度在32位和64位的虚拟机(暂不思索开启紧缩指针的场景)中辨别为32个和64个Bits。

    Synchronized锁对象就存储在MarkWord中,下面是MarkWord的规划:

    32位虚拟机 (责任编辑:admin)