synchronized总结

2023-10-26

目录

一、synchronized的特性

1.1 原子性

1.2 可见性

1.3 有序性

1.4 可重入性

二、synchronized的使用

2.1 修饰普通方法

2.2 修饰静态方法

2.3 修饰代码块

三、synchronized的锁机制

 3.1 偏向锁

3.2 轻量级锁

3.3 重量级锁

一、synchronized的特性

1.1 原子性

原子性是指一个操作或者多个操作,要么全部执行并且在执行的过程中不会被任何因素打断,要么就都不执行.

一条Java语句不一定是原子的,也不一定是一条指令,Java中对基本数据类型的变量读取和赋值操作都是原子性操作,也就是说这些操作是不可中断的,要么执行,要么不执行,像++,+=等操作符就不是原子的,他们是分成读取 计算 赋值几步操作的,有可能这些步骤还未完成就被赋值了,这就是脏读问题,无法保证原子性.

synchronized修饰的类或对象的所有操作都是原子的,因为在执行操作之前必须先获得类或对象的锁,直到执行完才能释放。

1.2 可见性

可见性是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的。 synchronized和volatile都具有可见性,其中synchronized对一个类或对象加锁时,一个线程如果要访问该类或对象必须先获得它的锁,而这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性

1.3 有序性

 有序性程序执行的顺序按照代码先后执行 ,synchronized和volatile都具有有序性,Java允许编译器和处理器对指令进行重排,但是指令重排并不会影响单线程的顺序,它影响的是多线程并发执行的顺序性。synchronized保证了每个时刻都只有一个线程访问同步代码块,也就确定了线程执行同步代码块是分先后顺序的,保证了有序性。

1.4 可重入性

synchronized和ReentrantLock都是可重入锁。当一个线程试图操作一个由其他线程持有的对象锁的临界资源时,将会处于阻塞状态,但当一个线程再次请求自己持有对象锁的临界资源时,这种情况属于重入锁。通俗一点讲就是说一个线程拥有了锁仍然还可以重复申请锁。

  1. 既是悲观锁,也是乐观锁,开始时是乐观锁, 如果锁冲突频繁, 就转换为悲观锁.
  2. 既是轻量级锁,也是重量级锁(自适应),开始是轻量级锁实现, 如果锁被持有的时间较长, 就转换成重量级锁.
  3. 轻量级锁部分基于自旋锁实现,重量级锁部分基于挂起等待锁来实现
  4. 不是读写锁
  5. 是非公平锁
  6. 是可重入锁 

二、synchronized的使用

2.1 修饰普通方法

多线程环境下,每次只能有一个线程访问该方法。

public synchronized void func() {
    //代码
}

2.2 修饰静态方法

就是给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得 当前 class 的锁。因为静态成员不属于任何一个实例对象,是类成员( static 表明这是该类的一个静态资源,不管 new 了多少个对象,只有一份)。所以,如果一个线程 A 调用一个实例对象的非静态 synchronized 方法,而线程 B 需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁

synchronized void staic Func() {
  //代码
}

2.3 修饰代码块

   this 代表当前实例对象,锁住的是当前实例:

synchronized(this) {
    for (int i = 0; i < 10; i++) {
		//代码
    }
}

.class锁住的是当前类的 class 对象锁:

synchronized(Main.class) {
    for (int i = 0; i < 10; i++) {
        //代码
    }
}

synchronized 关键字加到 static 静态方法和 synchronized(class) 代码块上都是是给 Class 类上锁。

synchronized 关键字加到实例方法上是给对象实例上锁。

三、synchronized的锁机制

从JDK5引入了现代操作系统新增加的CAS原子操作( JDK5中并没有对synchronized关键字做优化,而是体现在J.U.C中,所以在该版本concurrent包有更好的性能 ),从JDK6开始,就对synchronized的实现机制进行了较大调整,包括使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除、锁粗化、偏向锁、轻量级锁这些优化策略。由于此关键字的优化使得性能极大提高,同时语义清晰、操作简单、无需手动关闭,所以推荐在允许的情况下尽量使用此关键字,同时在性能上此关键字还有优化的空间。

锁主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。

 3.1 偏向锁

第一个尝试加锁的线程, 优先进入偏向锁状态.偏向锁不是真的 “加锁”, 只是给对象头中做一个 “偏向锁的标记”, 记录这个锁属于哪个线程.如果后续没有其他线程来竞争该锁, 那么就不用进行其他同步操作了(避免了加锁解锁的开销)

如果后续有其他线程来竞争该锁(刚才已经在锁对象中记录了当前锁属于哪个线程了, 很容易识别 当前申请锁的线程是不是之前记录的线程), 那就取消原来的偏向锁状态, 进入一般的轻量级锁状态.偏向锁本质上相当于 “延迟加锁” . 能不加锁就不加锁, 尽量来避免不必要的加锁开销.

3.2 轻量级锁

随着其他线程进入竞争, 偏向锁状态被消除, 进入轻量级锁状态(自适应的自旋锁).此处的轻量级锁就是通过 CAS 来实现.

通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)如果更新成功, 则认为加锁成功如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU).自旋操作是一直让 CPU 空转, 比较浪费 CPU 资源.因此此处的自旋不会一直持续进行, 而是达到一定的时间/重试次数, 就不再自旋了.也就是所谓的 “自适应”

3.3 重量级锁

如果竞争进一步激烈, 自旋不能快速获取到锁状态, 就会膨胀为重量级锁  执行加锁操作, 先进入内核态在内核态判定当前锁是否已经被占用 如果该锁没有占用, 则加锁成功, 并切换回用户态.如果该锁被占用, 则加锁失败. 此时线程进入锁的等待队列, 挂起. 等待被操作系统唤醒.经历了一系列的沧海桑田, 这个锁被其他线程释放了, 操作系统也想起了这个挂起的线程, 于是唤醒 这个线程, 尝试重新获取锁

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

synchronized总结 的相关文章

  • 为什么 Hashtable 不允许空键或空值?

    正如 JDK 文档中所指定的 Hashtable 不允许空键或空值 HashMap 允许一个空键和任意数量的空值 为什么是这样 Hashtable 是较旧的类 通常不鼓励使用它 也许他们看到了对 null 键的需要 更重要的是 null 值
  • Java - 将无符号十六进制字符串解析为有符号长整型

    我有一堆十六进制字符串 其中之一是 d1bc4f7154ac9edb 这是 3333702275990511909 的十六进制值 如果执行 Long toHexString d1bc4f7154ac9edb 这与您得到的十六进制相同 现在
  • 使用 TLS PSK 加密时如何正确检测流结束?

    我已经准备好了一个简单的 TLS PSK 客户端测试用例 https github com afarber jetty newbie tree master TlsPskClient2 src main java de afarber tl
  • openFileOutput 在单例类中无法正常工作 - 想法/解决方法?

    作为一名 Android 开发新手 我遇到了一些奇怪的问题 我想创建一个类 它方法其他类 活动 任何可以用于以某种特殊方式处理文件的类 假设为了简单起见 我们将记录一些内容 如果我在活动中执行以下操作 例如在 OnClick 侦听器中 则一
  • ZeroDateTimeBehavior=convertToNull 在使用 hibernate 的 jdbc url 中不起作用

    通过 extern 属性文件 url 指定如下 jdbc mariadb xxxxx 3306 xxxxx zeroDateTimeBehavior convertToNull 连接工作正常并且能够查询数据库 通过休眠 我创建了一个映射到带
  • java中高效的输入流到字符串方法

    因此 我在 Java 中的 诚然非常简单 应用程序上运行探查器 令我惊讶的是 仅次于需要在时间上发出 HTTP 请求的方法的是我的方法 inputStreamToString方法 目前它的定义如下 public static String
  • Jenkins 未显示 Maven 编译器错误

    在 Jenkins 中构建多模块 maven 3 项目时 如果出现构建错误 我们会收到一条神秘消息 表明 Maven 编译器插件失败 这在上周才刚刚开始发生 INFO BUILD FAILURE INFO INFO Total time 1
  • 如何杀死 Java Future?

    我正在开发的服务使用 Future 来并行运行多个任务 每个任务最多可能需要一分钟才能完成 然而 外部库似乎有问题 因为在某些情况下 2 的时间 它不会返回 在这些情况下 我想给出 2 分钟的等待时间 如果还没有返回 我想杀死 future
  • 如何在正则表达式中编写可选单词?

    我想编写一个识别以下模式的 java 正则表达式 abc def the ghi and abc def ghi 我试过这个 abc def the ghi 但是 它没有识别第二种模式 我哪里出错了 abc def the ghi 删除多余
  • 如何使用 aether 从 Java 找到最新版本的 Maven 工件?

    他们的文档非常薄弱 我无法弄清楚 我找到了部分答案here https stackoverflow com questions 27428068 how to retrieve the latest also snapshot versio
  • java:为什么主线程等待子线程完成

    我有一个简单的java程序 主线程 main 创建并启动另一个线程t class T extends Thread Override public void run while true System out println Inside
  • 如何获取 JDBC 中 UPDATE 查询影响的所有行?

    我有一项任务需要使用更新记录PreparedStatement 一旦记录被更新 我们知道更新查询返回计数 即受影响的行数 但是 我想要的不是计数 而是受更新查询影响的行作为响应 或者至少是受影响的行的 id 值列表 这是我的更新查询 UPD
  • 为 REST API 生成 Swagger UI 文档

    我使用 Java 中的 JAX RS Jersey 开发了 REST API 我想为其转换 生成基于 Swagger 的 UI 文档 谁能以简单的方式告诉我如何做到这一点的精确 步骤 很抱歉 他们网站上给出的步骤对我来说有点模糊 有多种方法
  • 如何在 JASPIC 中保存经过身份验证的用户?

    我开发了一个安全认证模块 SAM 并实现了validateRequest方法 我还有一个简单的 Web 应用程序配置为使用此 SAM In my validateRequest方法 我检查 clientSubject 并设置一个Caller
  • Hybris:如何在impex中导入zip文件中的媒体?

    我知道我们可以导入未像这样压缩的图像 siteResource jar com project initialdata constants ProjectInitialDataConstants projectinitialdata imp
  • 线程数组?

    所以我在理解如何避免线程的顺序执行时遇到了问题 我试图创建一个线程数组并在单独的循环中执行 start 和 join 函数 这是我现在拥有的代码示例 private static int w static class wThreads im
  • 如何在不使用 -cp 开关的情况下在 Groovy 中自动加载数据库 jar?

    我想简化调用 Oracle 数据库的 Groovy 脚本的执行 如何将 ojdbc jar 添加到默认类路径以便我可以运行 groovy RunScript groovy 代替 groovy cp ojdbc5 jar RunScript
  • 使用 Hibernate Envers 的复合表

    我有一个带有复合表的应用程序 其中包含一个额外的列 一切正常 直到我们添加 Hibernate Envers Audited org hibernate MappingException 无法读取 no pack response Resp
  • junit4 使用特定测试方法创建测试套件

    在 junit4 中 我想执行来自不同类的特定测试方法 即想要使用来自不同类的特定测试方法创建一个测试套件 假设我有两门课 public class Test Login Test public void test Login 001 Sy
  • FetchType.LAZY 不适用于休眠中的 @ManyToOne 映射

    简而言之 我的 Child 类与 Parent 类之间存在多对一的关系 我想加载所有的孩子 而不必加载他们的父母详细信息 我的孩子班级是 Entity public class Child implements Serializable I

随机推荐

  • iOS单例

    iOS开发中单例模式必不可少 是不是还在写单例的时候还写那一坨代码呢 这里提供一个宏 只需要简单的两句话就可以实现单例无论MRC还是ARC 使用方法 h中 import
  • @Control详解--Spring2.5

    一个简单的基于注解的 Controller 使用过低版本 Spring MVC 的读者都知道 当创建一个 Controller 时 我们需要直接或间接地实现 org springframework web servlet mvc Contr
  • LintCode统计数字:计算数字k在0到n中的出现的次数,k可能是0~9的一个值

    现在是2018 9 21 距离毕业还有不到两年的时间 情况乐观的话 我应该会在一年之内去找一份实习工作 对于找工作这件事 此刻的我还是有些惶恐 我无法确定清晰的职业方向和目标 对自己的知识储备也不自信 为了给即将面对的求职做些准备 我觉得有
  • CSDN证书记录(仅仅只是个人CSDN纪录)

    按照时间线来记录点点滴滴 1 2022年4月 安卓领域实力新星 2 2022年7月 笔耕不辍 3 2022年8月 博客专家
  • 今天百度索引量算是闹了个乌龙吗

    今天百度索引量算是闹了个乌龙吗 各大网站 不论大小 基本上都是索引量砍半 百度站长论坛更是热闹非凡 各种声音都有 百度服务器故障 百度算法大调整 网站被降权了等等 作为老站长的我发现索引量大幅下降后 立马看了百度站长平台中的其他站点 发现都
  • Xilinx FPGA 7系列 GTX/GTH Transceivers (1)

    初识Xlilix GTX 1概述 Xilinx 7系列FPGA全系所支持的GT GT资源是Xilinx系列FPGA的重要卖点 也是做高速接口的基础 GT的意思是Gigabyte Transceiver G比特收发器 不管是PCIE SATA
  • 数据的储存

    数据的存储在C语言中无疑是一个难点 但是也要充满信心征服他的信心 翻过这座山 会看到更广阔的天空 基本数据类型 整型家族 浮点数家族 自定义类型 指针类型 空类型 大小端字节序介绍和判断 整形在内存中的存储 浮点型在内存中的存储 练习 基本
  • uva 11292

    水题 include
  • 2022年秋招求职#end——华为单板硬件

    九月初就在官网创建了简历 但是当时并没有投简历 记录中却是已经投递简历了 害我以为一直都是石沉大海的状态 十月底江哥问我华子怎么样 有没有消息 我才上去官网看 然后重新投递 第一个志愿是逻辑 就是江哥的部门 第二个志愿是老本行电源 然后十月
  • git --login-i_使用Git- Part -I:基础知识

    git login i 介绍 Git是由Linux OS的创建者Linus Torvalds创建的流行的分布式版本控制系统 因此 您可能已经猜到它首先用于版本控制Linux内核代码 它广泛用于大多数开放源代码和封闭源代码软件的开发中 得益于
  • 第四课,视图的显示选项和光照部分

    主要讲了视图的两部分 一个是光照等 一个是说了显示部分 外界的宏观部分
  • css实现渐变色

    日常中最常用到的渐变色是背景和边框 一条线的渐变色可以考虑使用div 然后根据需求设置高度 两种 首先来了解一下绘制渐变色的角度与方向 第一种 背景 使用到的属性为background 接下来看三个关于背景渐变最常用到的实例 有详细注释 方
  • Azure Key Vault(2):创建Azure Key Vault

    如果想要了解Key Vault是干什么的 可以看我的上一篇博文 这里我会说一下如何来创建Key Vault并使用它来保存一个D365连接字符串 如下 AuthType ClientSecret url https contoso 8080
  • 什么是泛型?

    目录 一 什么是泛型 二 泛型方法 三 泛型接口 四 通配符 4 1 通配符 4 2 上限通配符 4 3 下限通配符 4 4 类型擦除 一 什么是泛型 泛型 就是指在类定义时不会设置类中的属性或方法参数的具体类型 而是在类使用时 创建对象
  • request,response中文乱码问题

    request response中文乱码问题 request乱码 浏览器向服务器发送的请求参数中包含中文字符 服务器获取的请求参数的值是乱码 response乱码 服务器向浏览器发送的数据包含中文字符 浏览器中显示的是乱码 产生乱码的原因
  • Android多线程之同步锁的使用

    本文主要介绍了Android多线程之同步锁的使用 分享给大家 具体如下 一 同步机制关键字synchronized 对于Java来说 最常用的同步机制就是synchronized关键字 他是一种基于语言的粗略锁 能够作用于对象 函数 cla
  • STL:list

    首先包含头文件 include
  • 【vue3】使用reactive定义对象或数组时的巨坑

    vue3中 使用ref或者reactive定义数据 let ruleForm reactive appId serviceId creatorId 如果要修改appId的值 就是 ruleForm appId 123 如果此时ruleFor
  • 【C++深入探索】Copy-and-swap idiom详解和实现安全自我赋值

    任何管理某资源的类比如智能指针需要遵循一个规则 The Rule of Three 如果你需要显式地声明一下三者中的一个 析构函数 拷贝构造函数或者是拷贝赋值操作符 那么你需要显式的声明所有这三者 拷贝构造函数和析构函数实现起来比较容易 但
  • synchronized总结

    目录 一 synchronized的特性 1 1 原子性 1 2 可见性 1 3 有序性 1 4 可重入性 二 synchronized的使用 2 1 修饰普通方法 2 2 修饰静态方法 2 3 修饰代码块 三 synchronized的锁