synchronized 重量级锁分析

1. 背景

在JDK1.6以前,synchronized 的工作方式都是这种重量级的锁。它的实现原理就是利用 kernel 中的互斥量,mutex。主要是内核中的mutex 能够保证它是一个互斥的量。如果线程1拿到了 mutex,那么线程2就拿不到了。这是内核帮我们保证的。

至于为什么可以,可以去了解一下内核中的互斥量。

2. 为啥叫做重量级锁

内核需要去申请这个互斥量,必须要进入内核态。也就是这里需要用户态,内核态的切换。状态的切换,开销是比较大的。这就是重型锁的一个弊端。对于重型锁的一些主要的封装都是在 c 语言中的 pthread 这样一个库中,比如mutex_init, mutex_lock 等。之所以叫重量级锁,就是因为需要进入到内核态。

3. 能否在用户态实现一把互斥锁

我们不需要进入到内核态就能够获取到这样的一把锁,也就是在用户态就可以实现一把锁。

比如说,现在就有一把锁,就叫做 state。0:表示未被使用,1 表示锁被占用了。

lock 的实现

如果锁当前是被占用的状态,那么程序就一直死循环。如果某个时刻,有一个线程把锁释放了,那么就退出死循环,执行下一行 state = 1。而且持有者=当前线程。也就是 state = 0的时候,就可以任务当前线程可以拿到这把锁了。

unlock 的实现

释放锁的时候,首先需要判断一下当前持有锁的线程是不是当前线程。如果是当前线程,那么就将 state 置为0, 持有者 = null。

当前设计方式存在的问题

while(state==1); state = 1;其实可以认为这个是比较赋值俩步操作,先比较,符合条件了,再进行赋值。那么其实这不是原子性的。比如说在比较的时候,俩个线程同时进行了比较,这俩个线程同时发现state = 0,那么这俩个线程同时都去会执行 state = 1的操作,这俩个线程都认为自己拿到了锁,那么这个就产生了并发的问题了。

如何改进这个问题呢?

我们看到比较和赋值不是原子性的,在软件层面,我们也无法保证这俩步的原子性。所以,计算机给我们提供了原语,也就是 CAS。

那么我们来看一下如何改进呢? 我们把比较赋值这俩步操作,变成了一个原语操作,CAS。比较并交换。CAS中有三个参数,cas(state,0,1)。比较state的当前值是不是0,如果是0,那么就赋值为1。

再看看一下 unlock的操作。 在unlock操作中,其实也是一个比较赋值的操作,首先判断当前持有者是不是当前线程,如果是,再进行赋值。那为什么这里不需要用cas呢?因为必定是持有锁的线程才能执行到下一行。

而且赋值操作中,先赋值 持有者 = null。再赋值 state = 0。因为如果先执行 state = 0, 那么就相当于先释放掉这把锁了,另外一个线程就会执行 lock 成功,拿到锁,持有者 = 当前线程。那么就可能会带来一些问题。因为此时释放掉的锁并不是当前线程持有的锁。

这种锁也叫做自旋锁。

自旋锁的优点与缺点

自旋锁,spinLock。自旋锁不需要进入到内核态,整个程序的执行都是在用户态的,包括cas。但是cas不是计算机的原语吗?因为计算机的指令和用户态,内核态没有关系。

自旋锁当然也有缺点。 lock 操作如果一直没有拿到锁的话,会一直尝试。这是需要消耗cpu资源的。 所以自旋锁对于锁竞争比较激烈的情况下,是不适用的。

总结

mutex锁和自旋锁各有优缺点,那么我们能不能把这俩者结合一下呢? JDK 1.4 以前是借助内核中的 Mutex 互斥量; JDK1.4 以后是利用自旋锁,自旋n次以后,还是没有拿到锁的话,就切换到mutex。也就是将自旋锁和mutex进行了一个结合。因为mutex 加锁失败以后,会挂起,让出cpu资源。这样的话,算是对资源的一个合理利用。 JDK1.4以前,我们是可以设置自旋次数的,但是1.6以后,JDK可以自适应自旋,不用设置这个参数了。

当然现在我们所说的都是重量级锁。包括mutext, 自旋锁,自适应自旋锁。

synchronized 重量级锁分析相关推荐

  1. Java Synchronized 重量级锁原理深入剖析上(互斥篇)

    前言 线程并发系列文章: Java 线程基础 Java 线程状态 Java "优雅"地中断线程-实践篇 Java "优雅"地中断线程-原理篇 真正理解Java ...

  2. Java Synchronized 偏向锁/轻量级锁/重量级锁的演变过程

    前言 线程并发系列文章: Java 线程基础 Java 线程状态 Java "优雅"地中断线程-实践篇 Java "优雅"地中断线程-原理篇 真正理解Java ...

  3. 【Java 并发编程】线程锁机制 ( 锁的四种状态 | 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 | 锁竞争 | 锁升级 )

    文章目录 一.悲观锁示例 ( ReentrantLock ) 二.重量级锁弊端 三.锁的四种状态 ( 无锁状态 | 偏向锁 | 轻量级锁 | 重量级锁 ) 四.锁的四种状态之间的转换 ( 无锁状态 - ...

  4. 线程安全(中)--彻底搞懂synchronized(从偏向锁到重量级锁)

    接触过线程安全的同学想必都使用过synchronized这个关键字,在java同步代码快中,synchronized的使用方式无非有两个: 通过对一个对象进行加锁来实现同步,如下面代码. synchr ...

  5. yield方法释放锁吗_死磕Synchronized底层实现重量级锁

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 作者:farmerjohngit 链接:https://github.com/farmer ...

  6. Synchronized锁升级:无锁-> 偏向锁 -> 轻量级锁 -> 重量级锁

    一. 概述 1. Synchronized锁升级的原因 用锁能够实现数据的安全性,但是会带来性能下降.无锁能够基于线程并行提升程序性能,但是会带来安全性下降. 2. Synchronized锁升级的过 ...

  7. 12.synchronized的锁重入、锁消除、锁升级原理?无锁、偏向锁、轻量级锁、自旋、重量级锁

    小陈:呼叫老王...... 老王:来了来了,小陈你准备好了吗?今天我们来讲synchronized的锁重入.锁优化.和锁升级的原理 小陈:早就准备好了,我现在都等不及了 老王:那就好,那我们废话不多说 ...

  8. 偏向锁、轻量级锁、重量级锁,Synchronized底层源码终极解析!

    synchronized是掌握Java高并发的关键知识点,底层源码更是面试重灾区.本文从源码学习synchronized的原理,讲解对象头.偏向锁.轻量级锁.重量级锁等概念. 扫码关注<Java ...

  9. 操作系统锁的实现方法有哪几种_java 偏向锁、轻量级锁及重量级锁synchronized原理...

    Java对象头与Monitor java对象头是实现synchronized的锁对象的基础,synchronized使用的锁对象是存储在Java对象头里的. 对象头包含两部分:Mark Word 和 ...

最新文章

  1. linux 64平台上编译32位程序: GCC编译选项 -m64 -m32 -mx32
  2. 【Luogu1937】仓配置(贪心,线段树)
  3. boost::tokenizer模块相关的测试程序
  4. OpenGL 纹理Textures
  5. mybatis jar包_Java修行第039天---Mybatis框架
  6. 为什么“支付宝里没钱了”和“微信里没钱了”给人两种不同的感觉
  7. twilio_15分钟内使用Twilio和Stormpath在Spring Boot中进行身份管理
  8. 使用Drools 6.0进行部署
  9. mysql group by 两列_MySQL GROUP BY两列
  10. 【CF453D】 Little Pony and Elements of Harmony(FWT)
  11. 一步步编写avalon组件02:分页组件
  12. P1828 香甜的黄油 (spfa)
  13. 小米路由器mini WOL网络唤醒插件
  14. 文档隐写溯源技术分析
  15. 论用户体验测试:牛逼的功能千篇一律,好的体验万里挑一
  16. 京东后台:订单履约系统设计(下)
  17. RESTful理解与实践
  18. 编程的思想是什么,如何建立编程思想,如何训练和提高编程思想?
  19. 苹果 iOS 15 正式发布
  20. tensorflow 冻结梯度

热门文章

  1. 隐私政策-金庸作品集app
  2. Editplus 编译C++
  3. 基于A*算法的迷宫小游戏
  4. RabbitMQ延时消息队列
  5. 常用的工具类网址!!!程序员必备
  6. mysql银行催款提醒业务_今天你被银行催款了吗?
  7. Starling Feathers Controls Screen
  8. 内连接与外链接的区别
  9. 解决西电校园网若干问题
  10. Android:字母大小写转换