一、synchronized知识

  在谈论synchronized之前,我们需要了解线程安全问题的主要诱因。线程安全问题的主要诱因如下:

  • 存在共享数据(也称为临界资源)
  • 存在多条线程共同操作这些共享数据

  而解决线程安全的根本方法就是:同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再对共享数据进行操作。

  基于上述,引入了互斥锁,其具有两个特性:

  1. 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程的协调机制,这样在同一时间只有一个线程对需要同步的代码块进行访问。互斥性也称作操作的原子性。
  2. 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起不一致。

  需要注意的是,synchronized锁的不是代码,而是对象。

  根据获取锁的分类,可分为获取对象锁、获取类锁。

获取对象锁的两种方法:

1、同步代码块(synchronized(this),synchronized(类实例对象)),锁是小括号中的实例对象。

2、同步非静态方法(synchronized method),锁是当前对象的实例对象。

获取类锁的两种方法:

1、同步代码块(synchronized(类.class)),锁是小括号中的类的对象。

2、同步静态方法(synchronized static method),锁是当前对象的类对象(class对象)。

接下来,对对象锁和类锁进行总结对比:

1、有线程访问对象的同步代码块时,另外的线程可以访问该对象的非同步代码块;

2、若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问对象的同步代码块的线程会被阻塞;

3、若锁住的是同一个对象,一个线程在访问对象的同步方法时,另一个访问对象的同步方法的线程会被阻塞;

4、若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问对象的同步方法的线程会被阻塞,反之亦然;

5、同一类的不同对象的对象锁互不干扰;

6、类锁由于也是一种特殊的对象锁,因此表现和上述的1、2、3、4一致,而由于一个类只有一把对象锁,所以同一类的不同对象使用类锁将会是同步的;

7、类锁和对象锁互不干扰。

二、synchronized底层实现原理

  实现synchronized的基础:Java对象头+Monitor

  对象头的结构如下:

虚拟机位数 头对象结构 说明
32/64bit Mark Word 默认存储对象的hashcode,分代年龄,锁类型,锁标志位等信息。
32/64bit Class Metadata Address 类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的数据。

  下面是32bit的Mark Word的说明图:

  

  而对于Monitor,每个Java对象天生自带一把看不见的锁(内部锁/Monitor锁)。

  Monitor锁的竞争与释放如下图所示:

  

  在早期的Java版本中,synchronized属于重量级锁,依赖于Mutex Lock实现。线程之间的切换需要从用户态转换到核心态,开销很大。

  在Java 6之后,synchronized性能得到很大提升。主要是因为引入了:

  1:Adaptive spinning(自适应自旋)

  2:Lock Eliminate(锁消除)

  3:Lock Coarsening(锁粗化)

  4:Lightweight Locking(轻量级锁)

  5:Biased Locking(偏向锁)

  6:......

  下面对这些概念进行介绍。

  自旋锁与自适应自旋锁:

  自旋锁:在很多情况下,共享数据的锁定状态持续时间较短,切换线程不值得。就通过让线程执行忙循环等待锁的释放,而不让出CPU。缺点是若锁被其他线程长时间占用,会带来许多性能上的开销。用户使用preBlockspin来修改等待时间、次数,不好设定。

  这样的话,自适应自旋锁就出现了,它自旋的次数不固定,由前一次在同一个锁上的自旋时间及锁的持有者的状态来决定。

  锁消除:

  JIT编译时,对运行的上下文进行扫描,去除不可能存在竞争的锁,节省毫无意义的请求锁的时间。

  锁粗化:

  通过扩大加锁的范围,避免反复加锁和解锁。

  偏向锁:

  减少同一线程获取锁的代价。

  大多数情况下,锁不存在多线程竞争,总是由同一个线程多次获得。

  核心思想:如果一个线程获得了锁,那么锁就进入了偏向锁模式,此时Mark Word的结构也变为偏向结构,当该线程再次请求锁的时候,无需做任何操作,即获得锁的过程只需检查Mark Word的锁标记位为偏向锁以及当前线程ID等于Mark Word的ThreadID即可,这样就省去了大量有关锁申请的操作。

  不使用与锁竞争比较激烈的多线程场合。

  轻量级锁:

  轻量级锁是由偏向锁升级来的,偏向锁运行在一个线程进入同步块的情况下,当第二个线程加入锁竞争的时候,偏向锁就会升级为轻量级锁。

  使用场景:线程交替执行同步块。

  若存在同一时间访问同一锁的情况,就会导致轻量级锁膨胀为重量级锁。

三、synchronized和ReentrantLock的区别

  ReentrantLock称为重入锁,位于JUC包的locks,和CountDownLatch、FutureTask一样基于AQS实现。能够实现比synchronized更细粒度的控制,比如控制公平性。此外需要注意,调用lock()之后,必须调用unlock()释放锁。它的性能未必比synchronized高,并且是可重入的。

  ReentrantLock公平性的设置:

  ReentrantLock fairLock = new ReentrantLock(true);

  参数为true时,倾向于将锁赋予等待时间最久的线程;

  公平锁:获取锁的顺序按先后调用lock方法的顺序(慎用);

  非公平锁:抢占的顺序不一定,看运气;

  synchronized是非公平锁。

  ReentrantLock能够将锁对象化:

  判断是否有线程,或者某个特定线程,在排队等候获取锁;

  带超时的获取锁的尝试;

  感知有没有成功获取锁。

  ReentrantLock能够将wait/notify/notifyAll对象化。

  总结:

  1、synchronized是关键字,ReentrantLock是类;

  2、ReentrantLock可以获取锁的时间进行设置,避免死锁;

  3、ReentrantLock可以获取各种锁的信息;

  4、ReentrantLock可以灵活实现多路通知;

  5、机制:sync操作Mark Word,lock调用Unsafe类的park()方法。

Synchronized的基本知识、实现原理以及其与ReentrantLock的区别的更多相关文章

  1. synchronized锁机制的实现原理

    Synchronized 锁机制的实现原理 Synchronized是Java种用于进行同步的关键字,synchronized的底层使用的是锁机制实现的同步.在Java中的每一个对象都可以作为锁. J ...

  2. 风炫安全WEB安全学习第十九节课 XSS的漏洞基础知识和原理讲解

    风炫安全WEB安全学习第十九节课 XSS的漏洞基础知识和原理讲解 跨站脚本攻击(Cross-site scripting,通常简称为XSS) 反射型XSS原理与演示 交互的数据不会存储在数据库里,一次 ...

  3. Synchronized 与 ReentrantLock 的区别!

    来源:cnblogs.com/baizhanshi/p/7211802.html 之前栈长分享了重入锁的概念:<到底什么是重入锁,拜托,一次搞清楚!>,今天现来深入了解下 Synchron ...

  4. java web Session会话技术(原理图解+功能+与Cookie的区别+基本使用)

    java web Session会话技术(原理图解+功能+与Cookie的区别+基本使用) 这是我关于会话技术的第二篇文章,对 Cookie有不了解的兄弟可以点击下方的Cookie跳转 Cookie链 ...

  5. synchronized和 synchronized 了解偏向锁、轻量级锁、重量级锁的概念以及升级机制、以及和ReentrantLock的区别。

    并发 synchronized 了解偏向锁.轻量级锁.重量级锁的概念以及升级机制.以及和ReentrantLock的区别.       https://www.cnblogs.com/deltadeb ...

  6. (转)2.4.1 基础知识--添加服务引用与Web引用的区别

    <Web服务开发学习实录>第2章构建ASP.NET Web服务,本章我们将学习创建Web服务的各种方法,并重点对使用Visual Studio创建ASP.NET Web服务和修改Web服务 ...

  7. synchronized和ReentrantLock的区别

    synchronized和ReentrantLock的区别 synchronized是和if.else.for.while一样的关键字,ReentrantLock是类,这是二者的本质区别. 代写 既然 ...

  8. 转:synchronized和LOCK的实现原理---深入JVM锁机制

    JVM底层又是如何实现synchronized的? 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug ...

  9. volatile、Synchronized实现变量可见性的原理,volatile使用注意事项

    变量不可见的两个原因 Java每个线程工作都有一个工作空间,需要的变量都是从主存中加载进来的.Java内存模型如下(JMM): 线程访问一个共享的变量时,都需要先从主存中加载一个副本到自己的工作内存中 ...

随机推荐

  1. 一个简单的cmake例子

    一个简单的cmake例子CMakeLists.txt,生成动态库文件,可以指定发布目录. 尚不支持: 1.交叉编译环境配置 2.添加依赖库   #在当前目录新建一个build目录,然后cd build ...

  2. 总结Java常用到的六个加密技术和代码

    加密,是以某种特殊的算法改变原有的信息数据,使得未授权的用户即使获得了已加密的信息,但因不知解密的方法,仍然无法了解信息的内容.大体上分为双向加密和单向加密,而双向加密又分为对称加密和非对称加密(有些 ...

  3. #Java学习之路——基础阶段二(第六篇)

    我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...

  4. 学python走过的坑 三 不能实现的浏览器缩放功能

    公司一个项目,在启动web页面时,默认应该是打开项目页面,然后浏览器启动时总是打开一个广告页面,经理让写一个脚本,让电脑每次开机自启浏览器,且加载项目页面.浏览器自启和打开项目页面轻松搞定,这时问题来 ...

  5. 使用logdashboard进行可视化的日志追踪

    本文源码在Github可以找到下载 LogDashboard 如果你还不了解LogDashboard请看这里. LogDashboard 1.1版本支持请求追踪,虽然目前版本还没有发布.不过这个功能可 ...

  6. Asp.Net Core 轻松学-利用xUnit进行主机级别的网络集成测试

    前言     在开发 Asp.Net Core 应用程序的过程中,我们常常需要对业务代码编写单元测试,这种方法既快速又有效,利用单元测试做代码覆盖测试,也是非常必要的事情:但是,但我们需要对系统进行集 ...

  7. Java——泛型

    前言 一般的类和方法,使用的都是具体的类型:基本类型或者自定义的类.如果我们要编写出适用于多种类型的通用代码,那么肯定就不能使用具体的类型.前面我们介绍过多态,多态算是一种泛化机制,但是也会拘泥于继承 ...

  8. 如何在IIS上发布网站

    本片博客记录一下怎么用IIS发布一个网站,以我自己电脑上一个已经开发完成的网站为例: 1.打开项目 这是我电脑上的一个项目,现在我记录一下将这个项目发布到iis上的整个过程: 2.在vs2017中发布 ...

  9. ASP.NET Core的JWT的实现(自定义策略形式验证).md

    既然选择了远方,便只顾风雨兼程 __ HANS许 在上篇文章,我们讲了JWT在ASP.NET Core的实现,基于中间件来实现.这种方式有个缺点,就是所有的URL,要嘛需要验证,要嘛不需要验证,没有办 ...

  10. jQuery(八)、ajax

    1.jQuery.ajax(url[, settings]) 通过HTTP请求加载远程数据. 注意:所有的settings选择都可以通过$.ajaxSetup()函数来全局指定. 回调函数 在实际开发 ...