• synchronized详解(转)


    转载:https://www.cnblogs.com/yufeng218/p/13028549.html

    多线程编程中,有可能会出现多个线程同时访问同一个共享可变资源的情况;这种资源可能是:对象、变量、文件等。

    由于线程执行的过程是不可控的,所以需要采用同步机制来协同对对象可变状态的访问,那么我们怎么解决线程并发安全问题?

      实际上,所有的并发模式在解决线程安全问题时,采用的方案都是 序列化访问临界资源。即在同一时刻,只能有一个线程访问临界资源,也称作同步互斥访问。

    Java 中,提供了两种方式来实现同步互斥访问:synchronized 和 Lock

    synchronized 关键字:对于不同线程之间看到的是有序的,但是对于synchronized代码块之内的代码有可能会发生指令重排。

    一、锁

    1、同步器的本质就是加锁 

    加锁目的:序列化访问临界资源,即同一时刻只能有一个线程访问临界资源(同步互斥访问)

    不过当多个线程执行一个方法时,该方法内部的局部变量并不是临界资源,因为这些局部变量是在每个线程的私有栈中,因此不具有共享性,不会导致线程安全问题。

    2、锁类型

    隐式锁:Synchronized加锁机制是Jvm内置锁,不需要手动加锁与解锁Jvm会自动加锁跟解锁。

    显式锁:Lock;例如:ReentrantLock,实现juc里的Lock接口,实现是基于AQS实现,需要手动加锁跟解锁ReentrantLock lock(), unlock();

    3、锁体系

    (1)synchronized的锁升级:无锁,偏向锁,轻量级锁,重量级锁; 

    (2)共享锁:读锁; 排他锁:写锁;

    二、synchronized原理详解  

      synchronized内置锁是一种对象锁(锁的是对象而非引用),作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是可重入的。

    1、加锁方式

    (1)同步静态方法:锁是类对象

    (2)同步普通方法:锁是实例对象;(在spring容器中,Bean必须是单例的,否则加的synchronized没有什么作用)

    (3)同步代码块: 锁是括号里面的对象;

    扩展:使用其他方式加锁:

    (1)UnsafeInstance.reflectGetUnsafe().monitorEnter(obj); 和 UnsafeInstance.reflectGetUnsafe().monitorExit(obj);

    (2)ReentrantLock;

    2、synchronized底层原理  

      synchronized是基于JVM内置锁实现,通过内部对象Monitor(监视器锁)实现,基于进入与退出Monitor对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低。

      当然,JVM内置锁在1.5之后版本做了重大的优化,如锁粗化(Lock Coarsening)、锁消除(Lock Elimination)、轻量级锁(Lightweight Locking)、偏向锁(Biased Locking)、适应性自旋(Adaptive Spinning)等技术来减少锁操作的开销,内置锁的并发性能已经基本与Lock持平。

    synchronized关键字被编译成字节码后会被翻译成 monitorenter 和 monitorexit 两条指令分别在同步块逻辑代码的起始位置与结束位置。

     每一个对象被创建之后,都会在JVM内部维护一个与之对应的monitor监视器锁(ObjectMonitor对象)。当线程并发的去访问同步的代码块时,碰到了 monitorenter 指令的时候,这些线程要先去竞争这个对象的monitor对象。

    ObjectMonitor对象的部分代码:

    synchronized加锁加在对象上,对象是如何记录锁状态的呢?

        锁状态是被记录在每个对象的对象头(Mark Word)中,下面我们一起认识一下对象的内存布局。

    对象的内存布局  

      HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

    • 对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等;
    • 实例数据:即创建对象时,对象中成员变量,方法等;
    • 对齐填充:对象的大小必须是8字节的整数倍;

    对象头

    HotSpot虚拟机的对象头包括两部分信息,第一部分是“Mark Word”,用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等。这些信息随着锁的膨胀升级而不同,以 32位JVM为例:

     

  • 相关阅读:
    不等高cell的搭建(一)
    重复点击主界面(TabBar)按钮刷新界面--点击状态栏回到顶部
    如何学习新框架(保存图片到相册)
    上下拉刷新
    MVVM框架思想
    不等高cell的tableView界面搭建
    UITabBarController底层实现
    封装业务类
    RSS阅读器
    构造队列
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/16548450.html
Copyright © 2020-2023  润新知