当前位置: 首页 > news >正文

synchronized的详解、锁的升级过程和优缺点比较

本文 详细介绍Java中为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁轻量级 锁、重量级锁,以及锁升级过程。

Java中每一个对象都可以作为锁。具体表现形式为以下三种形式:

  • 对于普通的同步方法,锁是当前的实例对象
  • 对于静态同步方法,锁是当前类的Class对象
  • 对于同步方法块,锁是Synchronized括号里面的配置对象

演示:

Person类中的代码:

package com.qcby.demo1;public class Person {public int age;public String name;public int[] arr = {1,2,3};public String[] arr2 = {"aaa","bbb"};public Person son;//锁对象public synchronized void m1(){System.out.println("我是m1开始");try{Thread.sleep(4000);}catch(InterruptedException e){}System.out.println("我是m1结束");}//锁对象public  synchronized void m2(){System.out.println("我是m2开始");try{Thread.sleep(4000);}catch(InterruptedException e){}System.out.println("我是m2结束");}//锁类public synchronized static void m3(){System.out.println("我是m3开始");try{Thread.sleep(4000);}catch (InterruptedException e){}System.out.println("我是m3结束");}//锁类public synchronized static void m4(){System.out.println("我是m4开始");try{Thread.sleep(4000);}catch (InterruptedException e){}System.out.println("我是m4结束");}}

Test类中的代码:

package com.qcby.demo1;public class Test {public static void main(String[] args) {System.out.println("阿瑟东");Person ww = new Person();Thread x1 = new Thread() {@Overridepublic void run(){ww.m1();}};Thread x2 = new Thread() {@Overridepublic void run(){ww.m2();}};Thread x3 = new Thread(){@Overridepublic void run(){ww.m3();}};Thread x4 = new Thread(){@Overridepublic void run(){ww.m4();}};x1.start();x2.start();x3.start();x4.start();}}

结果展示:

1、调用同一个对象中的m1、m2方法时:

m2方法会等待m1方法结束之后才能开启

2、调用不同对象中的m1、m2方法时:

m1和m2方法几乎同时开启,同时结束

3、调用同一个类中的m3、m4方法时:

m4方法会等待m3方法结束之后才能开启

锁的升级和对比:

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是由同 一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁

当一个线程访问同步块并且获取锁的时候,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块的时候不需要进行CAS操作来加锁和解锁,只需要测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

  • 如果测试成功,表示线程已经获得了锁
  • 如果测试失败,则需 要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁)
    • 如果没有设置,则 使用CAS竞争锁;
    • 如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

偏向锁的撤销:偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放锁。

轻量级锁

当两个或以上的线程交替获取锁,但并没有在对象上并发的获取锁时,偏向锁升级为轻量级锁。在此阶段,线程采取CAS的自旋方式尝试获取锁,避免阻塞线程造成CPU在用户态和内核态间转换的消耗。

重量级锁

因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级 成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时, 都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮 的夺锁之争。

三种锁的优缺点的对比:

优点

缺点

适用场景

偏向锁

加锁和不加锁不需要额外的消耗,和事项非同步方法相比只存在纳秒级别的差距。

如果线程之间存在锁的竞争,会带来额外的锁撤销的消耗

适用于只有一个线程访问同步块场景

轻量级锁

竞争的线程不会阻塞,提高了程序的响应速度

如果一直得不到锁竞争的线程,适用自旋回消耗CPU

追求响应时间,同步块执行速度非常快

重量级锁

线程竞争不适用自旋,不会消耗CPU

线程阻塞,响应时间缓慢

追求吞吐量,同步块执行速度比较长

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Maven 解析:打造高效、可靠的软件工程
  • JavaSE:9、数组
  • 3. 进阶指南:自定义 Prompt 提升大模型解题能力
  • 记录word转xml文件踩坑
  • 机器学习特征构建与特征筛选
  • Vue3实现打印功能
  • LeetCode[中等] 3. 无重复字符的最长子串
  • 简洁明了!中缀表达式转为后缀表达式规则及代码
  • 第L6周:机器学习-随机森林(RF)
  • 计算机网络 ---- 计算机网络的体系结构【计算机网络的分层结构】
  • Python和MATLAB及C++信噪比导图(算法模型)
  • python绘制3d建筑
  • 数据清洗-缺失值填充-K-NN算法(K-Nearest Neighbors, K-NN算法)
  • 排队免单模式小程序开发
  • ElementUI 布局——行与列的灵活运用
  • 0x05 Python数据分析,Anaconda八斩刀
  • eclipse的离线汉化
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • JavaScript实现分页效果
  • JAVA之继承和多态
  • js作用域和this的理解
  • Mocha测试初探
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • oschina
  • python docx文档转html页面
  • React+TypeScript入门
  • Service Worker
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • 多线程 start 和 run 方法到底有什么区别?
  • 分享一份非常强势的Android面试题
  • 基于 Babel 的 npm 包最小化设置
  • 基于axios的vue插件,让http请求更简单
  • 简析gRPC client 连接管理
  • 聊聊hikari连接池的leakDetectionThreshold
  • 使用agvtool更改app version/build
  • MiKTeX could not find the script engine ‘perl.exe‘ which is required to execute ‘latexmk‘.
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #Linux(权限管理)
  • #职场发展#其他
  • (C语言)字符分类函数
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (理论篇)httpmoudle和httphandler一览
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (新)网络工程师考点串讲与真题详解
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转载)Linux 多线程条件变量同步
  • (转载)微软数据挖掘算法:Microsoft 时序算法(5)
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .net与java建立WebService再互相调用
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • @Async注解的坑,小心