深入理解Synchronized

java深入理解synchronized 消除锁是虚拟机另外一种锁的优化,这种优化更彻底,Java虚拟机在JIT编译时(可以简单理解为当某段代码即将第一次被执行时进行编译,又称即时编译),通过对运行上下文的扫描,去除不可能存在共享资源竞争的锁,通过这种方式消除没有必要的锁,可以节省毫无意义的请求锁时间,如下StringBuffer的append是一个同步方法,但是在add方法中的StringBuffer属于一个局部变量,并且不会被其他线程所使用,因此StringBuffer不可能存在共享资源竞争的情景,JVM会自动将其锁消除。 阅读详情

前言

大家好,我是fancy~

Synchronized想必大家在工作中一定有接触过,它算是Java并发场景下实现多线程安全一种比较直接的操作。有人会说它慢,确实。在JDK1.6之前,它有另一个名称叫做:重量级锁。但是从1.6版本起,它就在不断被优化。现如今已经是很成熟的并发安全技术;所以关于Synchronized的考察也常常成为面试官青睐的话题。

本文我们会使用图解的方式解析Synchronized的使用和原理,让我们开始吧~

image-20220415211054872

对象锁和类锁

什么是Synchronized?Synchronized是Java中的一个关键字,中文被称为“同步锁”。顾名思义,它是一种锁,当某一时刻有多个线程对同一段程序进行操作时,能够保证只有一个线程能够获取到资源,因此保证了线程安全。

Synchronized主要有三种使用方式:

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

普通方法

Synchronized是一个关键字,当作用于一个普通方法的时候,这个方法便被加上了同步锁,意味着某一时刻只有一个线程可以操作访问这个方法:

public class fancySyncTest {
    public synchronized void method1(){
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] agrs) throws InterruptedException {
        final fancySyncTest fs = new fancySyncTest();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                fs.method1();
            }
        },"线程1获取到资源");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                fs.method1();
            }
        },"线程2获取到资源");

        t1.start();
        t2.start();
    }
}

这段代码有方法method1( ),它的功能就是打印出当前执行这段代码的线程,并且让它休眠5秒钟。然后我们开启两个线程,线程t1和t2,它们两个一起启动。

这段代码的执行顺序很简单,线程1或者线程2任意一个线程先去执行method1( )的内容,然后休眠5秒钟。完事就释放锁,下一个线程会继续执行:

image-20220415172850819

整个过程由于只有一个线程获取到这个方法,去执行方法里的内容,所以method1( )里的代码资源是线程安全的。

于是,当前哪个对象调用了这个方法,那么当前这段线程在执行的时候就让这个对象去访问这个方法。比如我是让对象fs去调用method1( ),那么这把锁就作用于当前的fs对象实例:

image-20220415171411731

静态方法

静态方法和普通方法的区别只有一个,就是Synchronized关键字是作用于静态方法的。但是仅仅这个区别,代表着锁的对象也是不同的。原因在于Java的静态关键字它和实例对象没有任何关系,它作用的资源是在类的初始化时期就加载的,所以它只能由每个类唯一的Class对象调用。当它作用于一个Class对象时,它就会将这一整个类都锁住,简称"类锁":

public class fancySyncTest {
    public static synchronized void method1(){
        try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] agrs) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                fancySyncTest.method1();
            }
        },"线程1获取到资源");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                fancySyncTest.method1();
            }
        },"线程2获取到资源");

        t1.start();
        t2.start();
    }
}

可以看出,这段由静态关键字修饰的代码和普通的方法没什么区别,唯一的区别就在于:由于method1( )是静态的,所有我们不用创建对象,可以直接由类实例fancySynTest直接调用!作为代价,这把锁锁住的对象也是直接覆盖了这个类。也就是说,当线程1执行的时候,没有别的线程可以访问这个fancySyncTest类:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NzoqxoUu-1650294217326)(https://cdn.jsdelivr.net/gh/fancy1996/Pic/image-20220415172714536.png)]

Synchronized修饰普通方法和静态方法的区别只有一个:粒度不同。类似于数据库中表锁和行锁的区别。

代码块

Synchronized可以锁住普通方法,也可以锁住一个类,那么它锁的粒度能否更小呢?是的,它还能锁住一段简易的代码块。那么Synchronized如何定义一段代码块呢?其实定义一下作用的对象,然后将代码用括号{ }包裹起来就可以了:

public class fancySyncTest {
    public synchronized void method1(){
        synchronized (this) {
            // 逻辑代码
        }
    }
}

代码块锁住的对象就是后面括号里的东西。比如这里的synchronized (this),意味着只有当前对象才可以访问这段代码块,你也可以定义为其它对象。

Synchronized原理

其实,Synchronized只是Java中的一个关键字,那么它底层是如何真正意义地实现锁呢?答案就是monitor监视器锁。无论是synchronized代码块还是synchronized方法,其线程安全的语义实现最终依赖的都是monitor,它才是真正意义上的锁。

为了得到Synchronized的底层代码,我们先写一段简单demo:

public class fancySynchronizedTest {
    public synchronized void method1() {

    }
    public void method2() {
        synchronized (this){

        }
    }

    public static void main(String[] args) {
        fancySynchronizedTest test = new fancySynchronizedTest();
        test.method1();
        test.method2();
    }
}

然后对它使用java-c 反编译,得到以下文件:

public class fancySynchronizedTest {
  public fancySynchronizedTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public synchronized void test1();
    Code:
       0: return

  public void test2();
    Code:
       0: aload_0
       1: dup
       2: astore_1
       3: monitorenter  //monitor加锁
       4: aload_1
       5: monitorexit  //monitor解锁
       6: goto          14
       9: astore_2
      10: aload_1
      11: monitorexit //monitor异步退出解锁
      12: aload_2
      13: athrow
      14: return
    Exception table:
       from    to  target type
           4     6     9   any
           9    12     9   any

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class SynchronizedTest
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #4                  // Method test1:()V
      12: aload_1
      13: invokevirtual #5                  // Method test2:()V
      16: return
}

可以看到,test2( )在加上了synchronized同步代码块后,会输出以下指令:monitorenter和monitorexit。

monitorenter存在于同步代码块开始的位置,而monitorexit存在于同步代码块结束的位置,它们分别代表着获取锁和释放锁。每一个monitorenter都必须对应一个monitorexit。并且,每一个对象在其堆内存的数据结构中,它的对象头都会关联一个完整的monitor结构。

为了让大家更熟悉monitor,我们带大家来阅读一下monitor的源码。

对于我们通常使用的HotSpot虚拟机,monitor是由ObjectMonitor实现的。其源码是用c++来实现的,位于HotSpot虚拟机源码ObjectMonitor.hpp文件中,我们可以在社区版本的JDK上阅读到,因为它是开源的:

image-20220415100447722

注:该源码版本为jdk8u的社区版open jdk

我们需要关注该图上的三个变量:_owner、_WaitSet、_EntryList ,因为monitor就是通过它们,来实现上锁与释放锁的。我们先来看看这三个变量的定义:

_EntryList:

image-20220415101201827

它的定义为:阻塞在路口处的线程的集合

再来看看_WaitSet:

image-20220415101351227

它的定义为:处于等待监视器的线程的集合

最后看看变量_owner:

image-20220415101614887

它的意思是指向持有锁的线程。

所以,它的完整过程就是如下所示:

image-20220415104812743

monitor自身会设置一个变量count来作为计数器维护这把可重入锁,当没有线程获取这把锁的时候,它的值为0,如果有一个线程获取这把锁,它的值就会+1,并且设置该线程为锁的持有者。_owner指向的就是当前持锁线程。如果该线程已经占用该锁,并且重新进入,那么count的值就会+1。当执行到monitorexit的时候,count的值就会-1,直到monitor值为0的时候,该持锁线程会进入到WaitSet里面,将状态改为等待状态,让其他处于EntryList里的阻塞线程重新自旋获取这把锁。

以上就是完整的monitor获取锁和释放锁的过程。不知道你是否会觉得它和AQS的原理很像?其实这些底层架构设计的思想都是相通的。

锁的优化

可能是意识到Synchronized作为重量级锁性能上的不足,从jdk1.6开始Java团队就对它进行了优化。通过各种各样的手段,如自旋锁、偏向锁、轻量级锁等技术来减少锁的开销,那么我们就来解释一下这些锁操作以及升级过程。

自旋锁

首先聊聊自旋锁,自旋锁顾名思义就是自旋。当一个线程在获取锁的时候,如果该锁已被其它线程获取到,那么该线程就会去循环自旋获取锁,不停地判断该锁是否能够已经被释放,自选直到获取到锁才会退出循环。通常该自选在源码中都是通过for(; ;)或者while(true)这样的操作实现,非常粗暴。

那么都说是自旋了,自旋就代表着占用cpu资源,使用自旋锁的目的是为了避免线程在阻塞和唤醒状态之间切换而占用资源,毕竟线程从阻塞状态切换到唤醒状态需要CPU从用户态转化为内核态,而频繁的状态切换就会导致CPU的资源浪费,所以引入了自选锁。但是自旋锁也必定要设置一个自旋的阈值,否则因为自旋长期占用CPU核心数,也是一种资源的浪费。在JDK1.6中默认的自旋次数为10次,也就是说如果一个线程自旋超过10次,那么它就会自动进入挂起状态从而节约资源。以下为自旋锁获取锁过程:

image-20220415113540947

自旋锁在JDK源码中有大量的应用,之后我们还会接触到。

锁消除

锁消除指的是虚拟机即时编译器在运行的时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行削除。那么如何确定这个锁是否需要进行削除?主要来源于逃逸分析的判断,如果判断到一段代码中,在堆上的所有数据都不会逃逸出去被其他线程访问到,那就可以把它们当作栈上数据对待,认为它们是线程私有的,同步加锁自然就无须进行。举个例子:

    public void method() {
        synchronized (new Object()) {
            //代码逻辑

        }
    }

这段代码里面,我们new了一个Object对象来作为锁对象,但是这个对象也只有在method( )中被使用,其完整的生命周期都在这个方法中,也就是说JVM在经过逃逸分析后会对它进行栈上分配,由于在底层变成了私有数据,那么也就无需加锁了。其被优化后的代码会变成:

    public void method() {
        //代码逻辑
    }

这就是锁的消除,JVM虚拟机在判断一段代码没必要加锁后,会消除该锁的存在。

那么我们再来看看什么是锁的粗化。

锁粗化

锁粗化指的是在JIT编译时,发现如果有一段代码中频繁的加锁释放锁,会将前后的锁合并为一个锁,避免频繁加锁释放锁。举个例子:

    public void method() {
        for(int i = 0;i < 100; i++) {
            synchronized (new Object()) {
            //代码逻辑
            
            }
        }
    }

大伙说,如果按照正常的synchronized步骤走,这个循环需要进行多少次的加锁解锁操作,这性能可想而知!

leader看了你这段代码估计想骂娘。。。

好在现在的JVM已经优化的足够好了。当你这段代码在即时编译时,JVM检测到你每一次都是对同一个对象加锁,那么就会把这一串连续频繁的加锁解锁操作优化成仅仅一次公共的加锁解锁操作,这样性能就提升了很多了:

    public void method() {
        synchronized (new Object()) {
            for(int i = 0;i < 100; i++) {
                //代码逻辑
                
            }
        }
    }

所以,所谓的锁粗化,就是通过增加锁的范围,减少锁的数量来减少开销。

偏向锁

在提偏向锁之前,我们需要先提一下一个Java对象在内存中是如何存储的。

一个对象在堆内存中由三部分区域组成,分别为:对象头(Header)、实例数据(Instance Data)和对其填充(Padding):

image-20220415174048551

其中对象头包括了两部分,一部分是关于堆对象的布局、类型、GC状态、同步状态和标识哈希码的基本信息,它被称为"Mark Word "。

另一部分是类型指针,是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

image-20220415174735512

那么我们今天的重点在于Mark Word,其结构如下:

image-20220415210609415

好了,在知道了对象头的重要结构Mark Word,我们就继续聊聊偏向锁。

偏向锁是JVM认为没有发生并发的场景下提供的锁。它是JDK 1.6中的重要引进,因为HotSpot团队发现在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低,引进了偏向锁。

所以这就是它为什么叫“偏向锁”。“偏”,就是偏心的“偏”、偏袒的“偏”,它的意思是这个锁会偏向于第一个获得它的线程,会在对象头存储锁偏向的线程ID,以后该线程进入和退出同步区域时只需要检查是否为偏向锁,即锁标志位以及ThreadID即可:

image-20220415210627665

轻量级锁

轻量级锁是JDK 1.6之中加入的新型锁机制,它名字中的“轻量级”是相对于使用monitor的传统锁而言的,因此传统的锁机制就称为“重量级”锁。
首先需要强调一点的是,轻量级锁并不是用来代替重量级锁的。引入轻量级锁的目的在于:在多线程交替执行同步块的情况下,尽量避免重量级锁引起的性能消耗,但是如果多个线程在同一时刻进入临界区,会导致轻量级锁膨胀升级重量级锁,所以轻量级锁的出现并非是要替代重量级锁。当该锁为轻量级锁时,其Mark Word的状态变化如下:

image-20220415210653082

重量级锁

在JDK1.6之前,Synchronized就是一把“重量级锁”。它需要依赖操作系统级别的mutex和condition variable来实现。重量级锁会让抢占锁的线程从用户态转变为内核态,所以开销很大:

image-20220415210709778

锁升级

锁升级,顾名思义就是锁的等级不断上升。因为锁是会消耗性能的,所以锁不断升级,它的性能就会越差。当然这一切都是为了满足安全、复杂的业务场景。

并且锁只会升级,不会降级:

image-20220415210002330

总结

本文我们详细地介绍了Synchronized的三种使用方式、它作为锁的特性、详细的原理以及七种锁的优化过程。Synchronized作为虚拟机级别的锁,无论是业务的使用还是面试,都是经常被照顾的对象,所以搞懂它就很重要。下一次我们会讲一讲它异父异母的亲兄弟:JDK级别的锁Lock,以及谈谈它们是如何经常拿出来被比较的~

Vivado FIR Complier_IP核使用方法 文章依靠该IP核对应手册PG149写的,因为笔者需求简单,没有深入挖掘功能,可以自行下载学习。 阅读详情

相关推荐

python实现语音信号的分帧、加窗、预处理

语音信号实现分帧、加窗、预处理音频文件读取预加重分帧加窗 音频文件读取 librosa是非常强大的python语音信号处理库。 读取音频: 使用语句librosa.load(path, sr=22050, mono=True, offset=0.0, duration=None)读取音频文件,默认的采样率是22050,若要保留音频的原始采样率,使用sr=None。 其中: path:表示音频文件的路径 sr:表示采样率 mono:bool,是布尔类型,表示是否将信号转换为单声道 offset:float,后

weixin_45272908的博客 1万+

synchronized锁不住?

当synchronized遇上基本类型的封装类型对象时,锁不住?不废话,上代码public class Test { static Integer lock = new Integer(1); public static void main(String[] args) throws InterruptedException { Thread thread1 = ne

weixin_39471786的博客 2459

13-单片机模块化程序: 单片机AT指令配置模块程序模板(非阻塞版)

资料源码:https://gitee.com/yang456/OpenProgrammingModuleForMCU.git 点击加入群聊【单片机,物联网,上位机】: 说明1:知识从未如此性感。 烂程序员关心的是代码,好程序员关心的是数据结构和它们之间的关系! 说明2:学的是思想,而非程序!此代码思路适用于所有的单片机。 说明3:学会以后,下面的代码可能会跟你一辈子! 说明4:这一系列文章是为大幅度裁剪本人博客文章!使博客文章更有条理。便于推其它教程! 拷贝这两个文件到自己的工程 ..

杨奉武的博客 1280

线程锁(ReentrantLock、synchronized)为何不能用作分布式锁

1、为什么使用分布式锁 分布式锁主要应用在大型的分布式架构场景,分布式架构可以简单理解为将一个Web应用,部署在多个应用服务器上: 分布式锁适用于分布式架构场景,例如: 商品秒杀 抢优惠卷 如果没有保证线程安全,就可能会出现商品超卖、优惠卷发超等现象,例如下图代码: 我们会判断商品库存是否大于0,如果有库存就会将库存 - 1,不过有个问题,如果同时有多个用户(多线程)同时发送请求给接口,例如三个用户同时请求接口,同时获取商品库存、扣除库存,很有可能商品库存最终只扣除1次,这时候数据安全性就得不到保障

保持学习 3006

银河麒麟Arm64 v10 sp1系统QT5.12.8离线环境配置全攻略

本文详细介绍了在银河麒麟Arm64 v10 sp1系统上配置QT5.12.8离线开发环境的完整流程。从安装包获取、依赖检查到环境变量配置,逐步指导开发者解决飞腾处理器架构下的常见问题,包括OpenGL库冲突、中文乱码处理等,特别适合军工、政务等需要离线部署的场景。

weixin_26899659的博客 505

VisionMaster图像源模块的5个隐藏功能:从自动切换到二次开发接口

本文深入解析了VisionMaster图像源模块的5个隐藏功能,从基础的自动切换与字符触发过滤,到高级的脚本扩展与基于COM组件的二次开发接口。这些功能能显著提升工业视觉项目的自动化水平、灵活性与系统集成能力,帮助开发者实现更高效的离线测试流水线和外部精确控制。

rgv23456789的博客 651

java线程安全总结

原文: http://www.iteye.com/topic/806990 http://www.iteye.com/topic/808550 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣。已经拟好了提纲,大概分为这几个主题: java线程安全,java垃圾收集,java并发包详细介绍,java profile和jvm性能调优 。慢慢写吧。本人j...

web开发 642

警惕!数字签名伪造的攻防演练:用SigThief克隆证书的真实测试(Windows环境)

本文深入探讨了Windows环境下数字签名伪造的攻防技术,详细介绍了使用SigThief工具进行签名提取与克隆的实战步骤。通过真实测试案例,揭示了数字签名安全机制的潜在漏洞,并提供了有效的防御策略和检测技术,帮助安全人员提升系统防护能力。

weixin_42530732的博客 408

java线程同步代码块_线程间的同步与通信(1)——同步代码块Synchronized

前言同步代码块(Synchronized Block) 是java中最基础的实现线程间的同步与通信的机制之一,本篇我们将对同步代码块以及监视器锁的概念进行讨论。什么是同步代码块(Synchronized Block)同步代码块简单来说就是将一段代码用一把锁给锁起来, 只有获得了这把锁的线程才访问, 并且同一时刻, 只有一个线程能持有这把锁, 这样就保证了同一时刻只有一个线程能执行被锁住的代码.这里...

weixin_26824299的博客 539

如何把DeepSeek这个奈斯工具接入到Pycharm里

DeepSeek接入到Pycharm中,提高编程效率,以及帮助解决遇到的问题。

学无止境,何以言满 2622

从Oracle迁移数据到Hadoop

目标:把Oracle 下的数据文件迁移到 Hadoop , 数据表都是上亿条,每个数据表的空间都超过100G。 关键是建立数据文件是UTF8格式,这样数据中的汉字在Hadoop 里显示才正常。 平台:CentOS 6.10 工具:Python 2.7 cx_Oracle 库 Oracle10.2.0.4.0 Hadoop 2.7.2-transwarp-5.2.1 1. 查看表...

预则立 4233

并发编程七:深入理解synchronized(上)

深入理解synchronized(上) Java共享内存模型带来的线程安全问题 public class SyncDemo { private static int count = 0; public static void increment(){ count++; } public static void decrement(){ count--; } public static void main(String[] args) throws InterruptedException

admin522043032的博客 1001

hpm6750evk2开发板(四)TCP回送(1000M网口)

再接下来我们修改代码,先找到配置网速的地方,肯定是在enet的初始化函数里面,我们一个函数一个函数找,也可以用单步调试一步一步找,结果发现是在enet_init函数里面调用的rtl8211_basic_mode_default_config函数配置网速的,我们把enet_phy_port_speed_100mbps改为enet_phy_port_speed_1000mbps,重新编译运行试试。首先我们复制一份lwip_tcpecho代码,重命名为lwip_tcpecho_RGMII,如下图所示。

Silas1750的博客 920

深入理解synchronized关键字

概念 是 java 中的一个关键字,作用于对象,多线程并发访问此对象时起到同步互斥的作用,可重入 基本用法 作用在对象 给实例对象加锁 作用在方法 给实例对象加锁 作用在静态方法 给类对象加锁 实现原理 作用在对象上 编译成字节码时会生成2个指令,monitorenter和monitorexist monitorenter标识加锁,monitorexist 标识解锁 加解锁需要一个位置来记录对象的解决锁状态 每个对象有一个对象头,对象头中有2个关键数据 mark word klass pointe

MuskMelon 302

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

从字节码层面深入理解synchronized锁机制

理解synchronized的底层实现机制,可以帮助我们: 更好地诊断死锁问题 合理选择同步策略 优化高并发场景下的性能 深入理解JVM的运行时行为 最终需要记住:任何锁优化都不能替代良好的架构设计,在代码设计阶段就应该充分考虑并发控制策略。

weixin_51786043的博客 954

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深入理解synchronized

在获取锁时,是将当前线程插入到cxq的头部,而释放锁时,默认策略(QMode=0)是:如果EntryList为空,则将cxq中的元素按原有顺序插入到EntryList,并唤醒第一个线程,也就是当EntryList为空时,是后来的线程先获取锁。用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit,官方称它为“Mark Word”以上的结果可能是正数、负数、零。

星空下的博客 592

深入理解 synchronized

Java synchronized 关键字深度解析 本文全面剖析Java并发编程中的synchronized机制。从基本用法、字节码实现到底层原理,详细介绍了三种使用方式(实例方法、静态方法、代码块)及其对应的字节码指令(ACC_SYNCHRONIZED和monitorenter/monitorexit)。深入解析了对象头Mark Word在不同锁状态下的存储结构,以及重量级锁的ObjectMonitor实现机制。重点讨论了JDK 1.6引入的锁升级优化策略(偏向锁→轻量级锁→重量级锁),包括各阶段的工作原

qq_844085127的博客 1039

深入理解synchronized(二)——synchronized实现原理

前言 深入理解synchronized(一)——初识synchronized 在上一篇文章中,我们介绍了synchronized的作用以及用法,本文我们来探究下synchronized到底如何实现在对象加锁的。 Monitor Monitor可以理解为一个同步工具,也可以描述为一种同步机制,它通常被描述为一个对象。 与一切皆对象一样,所有的Java对象是天生的Monitor,每一个Java对象都有成为Monitor的潜质,因为在Java的设计中 ,每一个Java对象自打娘胎里出来就带了一把看不见的锁,它叫做

weixin_44271683的博客 717

并发锁机制之深入理解synchronized

思考: 两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?

输入知识,消化知识,输出知识,分享知识,教人让我学习更好,业精于勤荒于嬉,行成于思毁于随 1498

synchronized()_深入理解synchronized

并发编程中用到最多的关键字就是synchronized。下面来探究一下synchronized:synchronized如何使用?synchronized是如何实现同步加锁的,原理是什么?synchronized解决了并发编程的哪些问题?1 synchronized使用1.1 线程安全问题并发编程中,当多个线程同时访问同一个资源的时候,就会引发线程安全问题。由于每个线程执行的过程是不可控的,所以很...

weixin_39673303的博客 278
上一篇: 图解MVCC
下一篇: 原来这就是Java内存模型
是fancy呀
博客等级 码龄5年 6粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值