Java中的synchronized关键字

目录

1、synchronized是什么

2、synchronized的用法

synchronized可以用在方法或者代码块上,分别称为同步方法和同步代码块。

用法理解

3、synchronized的实现原理

⭐synchronized锁的对比

4、synchronized的优缺点

⭐扩展:synchronized 和 volatile 的区别?

⭐扩展:synchronized与Lock的区别?

小结


1、synchronized是什么

`synchronized` 是Java中的一个关键字,用于实现线程间同步。它可以被用来修饰方法或代码块,使得同一时刻只有一个线程可以执行被 `synchronized` 修饰的代码。

在Java中,当多个线程并发执行时,可能会出现数据竞争和不一致的情况。为了避免这种情况的发生,我们需要对共享变量进行同步控制,以保证同一时刻只有一个线程能够访问共享变量。

具体地说,当一个线程进入一个被 `synchronized` 修饰的方法或代码块时,它会尝试获取这个方法或代码块所属对象的锁(也称为监视器锁),如果获取不到锁就会阻塞等待。当另一个线程执行完该方法或代码块并释放了锁之后,等待的线程才能获取到锁并继续执行。

`synchronized` 的使用可以有效地避免多个线程同时访问共享变量造成的问题,但也会引入一定的性能损耗。因此,在需要进行线程同步时,建议使用 `synchronized` 来实现。但在高并发场景下,也可以考虑使用更轻量级的锁,例如 `ReentrantLock` 或 `Atomic` 类。

图片来源:https://www.cnblogs.com/three-fighter/p/14396208.html

2、synchronized的用法

synchronized可以用在方法或者代码块上,分别称为同步方法和同步代码块。

如果修饰的是普通方法,则锁作用于当前对象实例。如果是修饰静态方法,锁作用于类的Class实例。如果修饰的是代码块,作用于当前对象实例,则需要指定加锁对象。

1. 同步代码块:使用 synchronized 关键字修饰的代码块,可以指定一个对象作为锁,只有获得该锁的线程才能执行代码块。

synchronized后面括号里是一对象,此时,线程获得的是对象锁.例如:

public classMyThread implements Runnable{
    public static void main(Stringargs[]){
      MyThread mt=new MyThread();
        Thread t1=newThread(mt,"t1");
        Thread t2=newThread(mt,"t2");
        Thread t3=newThread(mt,"t3");
        Thread t4=newThread(mt,"t4");
        Thread t5=newThread(mt,"t5");
        Thread t6=newThread(mt,"t6");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        t6.start();
}   
public void run(){
    synchronized(this){
      System.out.println(Thread.currentThread().getName());
   }
}
public void method() {  
    synchronized (lockObject) { 
        //一次只能有一个线程进入 
        // 执行的代码  
    }  
}

在上述代码中,lockObject 是一个任意的对象,它将作为锁来确保同步。只有获取到 lockObject 对象的锁的线程才能执行同步代码块。

2. 同步方法:使用 synchronized 关键字修饰的方法,整个方法都会被视为同步代码块,同一时间只允许一个线程执行该方法。

public synchronized void synchronizedMethod() {
    // 需要同步的方法体
}

其中,锁对象可以是任意对象,只要在多个线程间能保持唯一性即可。通常,我们使用被访问对象的引用作为锁对象,以保证同一时刻只有一个线程可以访问该对象的相关操作。

需要注意的是,同步方法的锁是当前对象实例(即 this),而同步代码块可以指定任意的对象作为锁。在使用 synchronized 关键字时,需要选择合适的锁对象来确保线程安全,并避免死锁和性能问题。

用法理解

图片来源:synchronized(Java语言的关键字)_百度百科

3、synchronized的实现原理

它的实现原理主要基于Java 对象头、Monitor(监视器)以及对象的状态机等概念。当一个线程想要执行同步方法或同步块时,它必须先获取该方法或块的锁。如果其他线程已经持有该锁,那么当前线程就会进入阻塞状态,直到其他线程释放了它所持有的锁。这种机制可以避免多个线程同时访问共享资源,从而保证数据的一致性和安全性。

Java 对象头:在 Java 对象的内存布局中,每个对象都有一个头部信息。对象头是对象实例的一部分。它包含了对象的元数据信息,如对象的哈希码、锁状态标志等。在synchronized实现中,对象头被用来作为锁的标识。当一个线程执行synchronized方法时,它需要获取该方法所在对象的对象头锁。如果其他线程已经持有该锁,那么当前线程就会进入阻塞状态,直到其他线程释放了它所持有的锁。

图片来源:https://www.cnblogs.com/three-fighter/p/14396208.html

在Java中,synchronized的实现是通过对象头中的Mark Word来实现的。Mark Word是Java对象头中的一个重要组成部分,它包含了对象的哈希码、类型信息、锁状态等信息。当一个线程执行synchronized方法时,JVM会通过CAS(Compare and Swap)操作来尝试获取该对象的锁。如果获取成功,那么该线程就可以执行synchronized方法;如果获取失败,那么该线程就会进入阻塞状态。

有关CAS的内容可以查看博客:http://t.csdnimg.cn/8QSh6

64 位虚拟机 Mark Word 是 64bit,在运行期间,Mark Word里存储的数据会随着锁标志位的变化而变化。

图片来源:https://www.cnblogs.com/three-fighter/p/14396208.html

32位?

图片来源:synchronized 看这一篇就够了 - 知乎

Monitor(监视器):每个 Java 对象都与一个 Monitor 相关联,Monitor 是用来实现对象的锁机制的一种数据结构。它包含了锁的拥有者线程、等待队列、计数器等信息。

对象的状态机:Java 对象在并发环境下可以处于不同的状态,如无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态等。

当执行 synchronized 修饰的方法或代码块时,根据对象的状态,JVM 会进行如下处理:

1. 无锁状态:当对象没有被任何线程锁定时,进入 synchronized 代码块的线程将会尝试获取对象的锁。
2. 偏向锁状态:如果对象的锁处于无锁状态且没有竞争,那么进入 synchronized 代码块的线程可以直接获取锁,并将对象头中的线程ID更新为自己的ID,此时对象处于偏向锁状态。
3. 轻量级锁状态:如果对象处于偏向锁状态但出现了竞争,JVM 会尝试使用轻量级锁来实现同步。它通过CAS(比较并交换)操作来尝试获取锁,如果获取成功,则执行 synchronized 代码块;否则进入重量级锁状态。
4. 重量级锁状态:当多个线程争用同一个对象的锁时,JVM 会将对象的状态升级为重量级锁状态,此时线程会被阻塞,并加入到对象的等待队列中。只有拥有锁的线程释放锁后,等待队列中的线程才能被唤醒。

synchronized 看这一篇就够了 - 知乎

无论是偏向锁、轻量级锁还是重量级锁,它们都是通过在对象头中设置标记位和指针来实现的。JVM 会根据对象的竞争情况自动选择适合的锁状态,并进行状态的转换。

需要注意的是,synchronized 关键字的实现细节可能因不同的 JVM 实现而有所差异,上述描述是基于经典的 HotSpot JVM。

⭐synchronized锁的对比

优点缺点使用场景
偏向锁加锁和解锁不需要CAS操作,没有额外的性能消耗,和执行非同步方法相比仅存在纳秒级的差距如果线程间存在锁竞争,会带来额外的由于锁撤销的消耗适用于只有一个线程访问同步块的场景
轻量级锁竞争的线程不会阻塞,提高了响应速度如果线程一直得不到锁竞争的线程,使用自旋会消耗CPU性能追求响应时间,同步块执行速度非常快
重量级锁线程竞争不适用自旋,不会消耗CPU线程阻塞,响应时间缓慢,在多线程下,频繁的获取释放锁,带来的性能消耗很大追求吞吐量,同步块执行速度较长

4、synchronized的优缺点

优点
1. 简单易用:`synchronized` 关键字的语法简单,易于理解和使用,可以方便地确保多个线程对共享资源的安全访问。
2. 内置支持:作为Java语言的一部分,`synchronized` 关键字得到了JVM层面的支持,避免了用户自行实现线程同步机制的复杂性。
3. 可重入性:synchronized锁是可重入的,一个线程可以多次获得同一个锁,而不会造成死锁。

缺点
1. 粒度粗:使用 synchronized 关键字进行同步时,通常是对整个方法或代码块进行同步,这可能会导致一些不必要的等待,降低并发性能。
2. 无法中断:一旦进入 synchronized 代码块,除非获取到锁否则无法被中断,这可能会导致线程挂起的时间过长。
3. 性能开销:在某些情况下,使用 synchronized 可能会引入一定的性能开销,特别在高并发的场景下,这种开销可能会更加显著。
4. 局限性:synchronized 的锁是基于对象的,因此如果需要对不同的资源进行管理,就需要创建不同的对象锁,这可能会增加复杂性。

总的来说,`synchronized` 是一种简单且有效的线程同步机制,但在一些特定的情况下可能存在一些性能和灵活性上的局限性。在实际开发中,可以根据具体情况选择合适的同步机制,例如 `ReentrantLock`、`ReadWriteLock` 等来弥补 `synchronized` 的不足。

⭐扩展:synchronized 和 volatile 的区别?

synchronized 和 volatile 都是 Java 中用于保证多线程程序正确性的关键字,虽然它们的作用有所不同,但可以作为互补。

synchronized 关键字用于实现原子性操作和互斥访问。使用 synchronized 修饰的代码块或方法,在同一时间只允许一个线程进入临界区,其他线程需要等待当前线程执行完毕后才能进入。因此,synchronized 能够保证多个线程对共享资源的安全访问,并防止数据竞争和不一致性。

volatile 关键字用于保证可见性和禁止指令重排序。使用 volatile 修饰的变量,在多个线程之间保持可见性,当一个线程修改了变量的值,其他线程能够立即看到最新的值。此外,volatile 还能够禁止编译器和处理器对代码的优化,确保指令按照程序的顺序执行,避免出现意外的结果。

需要注意的是,volatile 不能保证原子性,如果需要进行复合操作,例如自增、自减、比较并交换等,仍然需要使用 synchronized 或 Lock 等机制来确保原子性。
 

⭐扩展:synchronized与Lock的区别?

图片来源:详解synchronized与Lock的区别与使用_synchronized 与lock 和redissionclient分布式锁区别-CSDN博客

小结

注意:在 JDK1.5之前synchronized是一个重量级锁,相对于juc包中的Lock,synchronized显得比较“重量级”。但是在 Java 6 之后 Java 官⽅对从 JVM 层⾯对synchronized进行了优化,例如“偏向锁”、“轻量锁”等等,并作为Java并发场景下实现多线程安全的一种比较直接的操作。

参考:

synchronized(Java语言的关键字)_百度百科

https://www.cnblogs.com/three-fighter/p/14396208.html

你真的了解 Synchronized 吗? - 知乎

synchronized 看这一篇就够了 - 知乎

详解synchronized与Lock的区别与使用_synchronized 与lock 和redissionclient分布式锁区别-CSDN博客
https://www.cnblogs.com/aspirant/p/11470858.html
 

万字干货|Synchronized关键字详解 - 知乎

深入Synchronized各种使用方法 - 一无是处的研究僧 - 博客园


感谢阅读,码字不易,多谢点赞!如有不当之处,欢迎反馈指出,感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/205670.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度解析 Spring Security 自定义异常失效问题:源码剖析与解决方案

🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…

leetcode面试经典150题——34 有效的数独(矩阵)

题目: 有效的数独 描述: 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现一次。 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出…

JAVA调优

1 JAVA虚拟机 1.1 基本组成 通常来说Java平台标准版(Java SE)包括 Java SE开发工具包(JDK)和Java SE运行时环境(JRE)。 JRE提供了运行以Java编程语言编写的applet和应用程序所必需的库,Java虚…

CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!)

B. AB Flipping 老规矩,自己要模拟一遍样例,发现样例还不够,就自己构造样例,这样做着做着就会有思路。 分析:假如现在有这样一个字符串 BBBAABABBAAA。会发现前三个和后三个一定是不会被操作的,因为不会满…

5、DMA Demo(STM32F407)

DMA简介 DMA 全称Direct Memory Access,即直接存储器访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。 DMA传输方式无需CPU直接控制传输,也没有中断处理方式那…

力扣295. 数据流的中位数(java,堆解法)

Problem: 295. 数据流的中位数 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 由于该题目的数据是动态的我们可以维护两个堆来解决该问题 1.维护一个大顶堆,一个小顶堆 2.每个堆中元素个数接近n/2;如果n是偶数,两个堆中的数据个数…

SpringCloud核心组件

Eureka 注册中心,服务的注册与发现 Feign远程调用 Ribbon负载均衡,默认轮询 Hystrix 熔断 降级 Zuul微服务网关(这个组件负责网络路由,可以做统一的降级、限流、认证授权、安全) Eureka 微服务的功能主要有以下几…

LLM之Agent(二):BabyAGI的详细教程

BabyAGI是一个 AI 支持的任务管理系统(Python脚本),使用 OpenAI 和 Pinecone API 创建, 优先级排序和执行任务。该系统背后的主要思想是基于先前任务的结果和预定义的目标创建任务。脚本然后使用 OpenAI 的自然语言处理(NLP&#…

数据结构学习笔记——二叉树的遍历和链式存储代码实现二叉树

目录 一、二叉树的遍历(一)二叉树的先序遍历(DLR)(二)二叉树的中序遍历(LDR)(三)二叉树的后序遍历(LRD)(四)二…

【古月居《ros入门21讲》学习笔记】07_创建工作空间和功能包

目录 说明: 1. 工作空间(workspace) 结构: 2. 创建工作空间和功能包 创建工作空间 编译工作空间 创建功能包 设置环境变量 3. 注意 同一个工作空间下,不能存在同名的功能包; 不同工作空间下,可以存在同名的功…

学习程序员必知必会的基础算法(收藏)

近年来学习python的程序员愈来愈多,有的同学选择了python培训机构,也有的人觉得自己天赋好选择了自学不管大家怎么去学习,在学习python基础的过程中,肯定离不开的就是基础算法,今天就为大家介绍几大学习中的基础算法。…

ffmpeg开发 环境配置

ffmpeg开发简图 1 下载ffmpeg开发包 https://ffmpeg.org/download.html 包含三个版本:Static、Shared以及Dev Static --- 包含3个应用程序:ffmpeg.exe , ffplay.exe , ffprobe.exe,体积都很大,相关的DLL已经被编译到exe里面去…

TDA4VM EVM开发板调试笔记

文章目录 1. 前言2. 官网资料导读3. 安装 Linux SDK4. 制作SD 启动卡5. 验证启动1. 前言 TDA4作为一般经典的车规级SOC芯片,基于它的低阶智驾方案目前成为各家智驾方案公司的量产首选,这也使得基于TDA4的开发需求陡增,开发和使用TDA4既要熟悉Linux驱应用开发,还要熟悉传统…

自建CA实战之 《0x02 Nginx 配置 https双向认证》

自建CA实战之 《0x02 Nginx 配置 https双向认证》 上一章节我们已经实现了Nginx上配置https单向认证,主要场景为客户端验证服务端的身份,但是服务端不验证客户端的身份。 本章节我们将实现Nginx上配置https双向认证,主要场景为客户端验证服…

基于Java SSM框架+Vue实现汉服文化平台网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现汉服文化平台系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个汉服文化平台网站 ,本系统将严格按照软件开发流程进行各个阶段的工作,采用B/S架构,面向对象编程思想进行项目开发。在引言中,作者将…

在gazebo里搭建一个livox mid360 + 惯导仿真平台测试 FAST-LIO2

在gazebo里搭建一个livox mid360 惯导仿真平台测试 FAST-LIO2 前言立方体平台加入 livox mid360 激光雷达加入IMU模块调整底盘大小 并设计调用接口测试 Fast-Lio2 前言 livox mid360 在官网一直没有货,在gazebo里可以仿真该雷达形式的点云。 但是其只发布雷达的数…

【电源专题】DC/DC电源FB分压电阻设计注意事项

在DC/DC电源中我们不可避免的会遇到FB分压电阻的取值,PCB设计等问题。如下所示随意打开一份同步降压稳压器规格书TPS56320X,规格书中的简化电路原理图就已经存在VFB管脚上的两个分压电阻。 很多工程师朋友们会误认为分压电阻只是简单的将输出电压缩小到参考电压,通过此电压来…

电子学会C/C++编程等级考试2023年03月(三级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:和数(2023.3) 给定一个正整数序列,判断其中有多少个数,等于数列中其他两个数的和。 比如,对于数列1 2 3 4, 这个问题的答案就是2, 因为3 = 2 + 1, 4 = 1 + 3。 时间限制:10000 内存限制:65536输入 共两行,第一行是数列中…

【接口自动化】selenium库也有大用场(获取cookie)

相信有些童鞋在做接口、或者说接口自动化测试的过程中会遇到这样的场景:测试的接口,必须是需要登录后才能发起请求成功的。 那么怎么解决呢? 本着团队协作的精神,我们就去让开发同学开个后门,给你个“万能”值&#x…

AntDB“超融合+流式实时数仓”——颠覆50年未变的数据库内核

流式处理引擎,颠覆50年未变的数据库内核 流式处理的概念 2001年9月11日,美国世贸大楼被袭击,美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司,承担了大量基础支撑软件研发的任务。其中200…