synchronized关键字同步原理

news2024/12/23 15:14:55

1.同步方法

public class Test {
    synchronized public static void testMethod(){}
    public static void main(String[] args) {
        testMethod();
    }
}
// 实现class文件的反汇编
java -c -v *.class

从字节码文件中可以看到同步方法根据flags标志中的ACC_SYNCHRONIZED来判别是否是同步方法。
在这里插入图片描述

1.1 锁对象

同步方法中并不是锁方法而是锁当前类的对象
:静态同步方法中锁是当前类,而不是对象。

  • 测试:methodA为同步方法,methodB为非同步方法,线程A调用methodA,线程B调用methodB。

TestMethod.java

public class TestMethod {

    synchronized public void methodA() {
        try {
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

ThreadA.java

public class ThreadA extends Thread{
    private TestMethod testMethod;

    public ThreadA(TestMethod testMethod) {
        super();
        this.testMethod  = testMethod;
    }
    @Override
    public void run() {
        super.run();
        testMethod.methodA();
    }
}

ThreadB.java

public class ThreadA extends Thread{
    private TestMethod testMethod;

    public ThreadA(TestMethod testMethod) {
        super();
        this.testMethod  = testMethod;
    }
    @Override
    public void run() {
        super.run();
        testMethod.methodA();
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        TestMethod testMethod = new TestMethod();
        ThreadA threadA = new ThreadA(testMethod);
        threadA.setName("a");
        ThreadB threadB = new ThreadB(testMethod);
        threadB.setName("b");
        threadA.start();
        threadB.start();

    }
}

运行结果:

methodA start ThreadName= a startTime=1690358535034
methodB start ThreadName= b startTime=1690358535034
methodA start ThreadName= a endTime=1690358540035
methodB start ThreadName= b endTime=1690358540035

结论:从结果可以看出,线程A持有TestMethod对象锁,线程B可以调用TestMethod的非同步方法。

  • 测试:methodA和methodB为同步方法,线程A调用methodA,线程B调用methodB。
    TestMethod.java
// 将methodB也修改为同步方法
public class TestMethod {

    synchronized public void methodA() {
        try {
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    synchronized public void methodB() {
        try {
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690359406773
methodA start ThreadName= a endTime=1690359411785
methodB start ThreadName= b startTime=1690359411785
methodB start ThreadName= b endTime=1690359416796

结论:从结果可以看出,线程A先持有TestMethod对象锁,虽然线程B调用的是methodB方法,但是也要等A释放锁之后才能执行。

2.同步代码块

public class Test2 {
    public void myMethod() {
        synchronized (this) {
            int age = 100;
        }
    }

    public static void main(String[] args) {
        Test2 test2 = new Test2();
        test2.myMethod();
    }
}

从字节码文件中可以看到同步代码块根据monitorenter和monitorexit来进行同步处理。
在这里插入图片描述

2.1 锁对象

和同步方法一样,同步代码块synchronized (this)锁的也是对象。
测试:
TestMethod.java

public class TestMethod {

     public void methodA() {
        try {
            synchronized (this) {
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            synchronized (this) {
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690361223642
methodA start ThreadName= a endTime=1690361228654
methodB start ThreadName= b startTime=1690361228654
methodB start ThreadName= b endTime=1690361233654

:此时(this)是锁的同一对象,所以methodA和methodB同步执行,如果使用不同对象锁,则互不影响。
测试:
TestMethod.java

public class TestMethod {

	// 也可以使用非对象做为锁。
    private String lock = new String();

     public void methodA() {
        try {
            synchronized (this) {
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }

    public void methodB() {
        try {
            synchronized (lock) {
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
                Thread.sleep(5000);
                System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果:

methodA start ThreadName= a startTime=1690361599813
methodB start ThreadName= b startTime=1690361599813
methodA start ThreadName= a endTime=1690361604820
methodB start ThreadName= b endTime=1690361604820

结论:从结果可以看出,虽然methodA和methodB中都存在同步代码块,但是因为锁对象不同,所以两个同步代码块的调用互不影响。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态内存管理面试题

动态内存管理面试题 文章目录 动态内存管理面试题一、第一题此代码存在的问题运行结果分析原因修改 二、第二题此代码存在的问题运行结果分析原因修改 一、第一题 代码如下&#xff08;示例&#xff09;&#xff1a; #include<stdio.h> #include<string.h> #incl…

快速学习Protobuf

目录 1. 什么是Protobuf&#xff1f; 2. 安装与设置 3. 定义消息 4. 编写.proto文件 5. 编译.proto文件 6. 序列化与反序列化 7. 使用Proto文件 8. Protobuf高级特性 1. 什么是Protobuf&#xff1f; 简介&#xff1a;Protobuf&#xff08;Protocol Buffers&#xff09;…

opencv python 训练自己的分类器

源码下载 一、分类器制作 1.样本准备 收集好你所需的正样本&#xff0c;和负样本&#xff0c;分别保存在不同文件夹 在pycharm新建项目&#xff0c;项目结构如下&#xff1a;has_mask文件夹放置正样本&#xff0c;no_mask文件夹放置负样本 安装opencv&#xff0c;把opencv包…

MySQL数据库面试题总结(2022最新版)

&#x1f436; 程序猿周周 ⌨️ 短视频小厂BUG攻城狮 &#x1f93a; 如果文章对你有帮助&#xff0c;记得关注、点赞、收藏&#xff0c;一键三连哦&#xff0c;你的支持将成为我最大的动力 本文是《后端面试小册子》系列的第 1️⃣ 篇文章&#xff0c;该系列将整理和梳理笔者作…

即时通讯im软件有哪些适合企业内部使用?

随着互联网的普及&#xff0c;即时通讯&#xff08;IM&#xff09;软件发挥着越来越重要的作用。它们为企业内部提供了高效的沟通方式&#xff0c;促进了团队沟通和工作效率的提升。以下是一些适合企业内部使用的即时通讯IM软件。 飞书 飞书是一款由字节跳动公司推出的企业级即…

python版本管理

安装anaconda3 conda conda search “^python$” conda创建新的 Python 环境&#xff0c;并指定你想要的 Python 版本&#xff1a; conda create -n myenv python<desired_python_version> 例如&#xff1a; conda create -n myenv python3.8.8 conda activate myen…

JS加载资源失败的解决办法

JS加载资源失败的解决办法 原文地址 JS加载失败导致问题 JS 也有可能加载失败&#xff0c;导致页面样式错乱&#xff0c;甚至白屏无法使用。这对用户体验是非常不利的&#xff0c;尤其是对于单页应用&#xff0c;如果 JS 加载不出来&#xff0c;用户就无法继续浏览页面了。 …

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…

(十六十七)时序数据库是怎么存储用户名和密码的从InfluxDB OSS迁移数据

以下内容来自 尚硅谷&#xff0c;写这一系列的文章&#xff0c;主要是为了方便后续自己的查看&#xff0c;不用带着个PDF找来找去的&#xff0c;太麻烦&#xff01; 第 16 章 时序数据库是怎么存储用户名和密码的 1、InfluxDB内部自带了一个用Go语言写的BlotDB&#xff0c;Blo…

大数据处理架构详解:Lambda架构、Kappa架构、流批一体、Dataflow模型、实时数仓

前言 本文隶属于专栏《大数据理论体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据理论体系 姊妹篇 《分布式数据模型详解&#xff1a;OldSQL &…

LDR6028DRP五V充电芯片OTG传数据充电高端方案

随着科学的进步&#xff0c;生产力的进步&#xff0c;时代的进步&#xff0c;电子产品的更新迭代&#xff0c;手机上面的接口越来越来少&#xff0c;甚至到后面手机没有任何接口。现在的手机只剩Type-c&#xff0c;那手机又要充电又要进行数据传输&#xff0c;那怎么办呢。那么…

Vue 常用指令 v-for 列表循环

v-for&#xff1a;根据数据生成列表结构&#xff0c;并且是响应式的&#xff0c;可以十分便捷的操作列表结构了。 至于是什么样的列表&#xff0c;就看你指令使用的位置了&#xff0c;列表的生成依赖于数据&#xff0c;所以先去定义数据。 它结合的类型挺多的&#xff0c;数组…

js实现框选截屏功能

实现的思路大概就是&#xff0c;先将dom转化为canvas画布&#xff0c;再对canvas进行裁切&#xff0c;然后通过canvas api生成图片&#xff0c;这里用到了一个库html2canvas 效果如图&#xff1a; 首先实现框选效果&#xff1a; const mousedownEvent (e) > {moveX 0;mo…

Java真的没出路了吗?

前言 并不是没有出路&#xff0c;Java当下确实是比较的内卷&#xff0c;但关键在于个人&#xff0c;可以看看不同地方&#xff08;这里主要举例北上广深一线城市&#xff09;对于Java开发工程师这个职位的具体要求&#xff1a; 在以下北上广深这些一线大城市的面试招聘当中不…

CAPL中有符号和无符号数据类型的若干问题

我们知道CAPL中的整数类型分为:无符号(unsigned)和有符号(signed)。 无符号类型有: byte (unsigned, 1 Byte)word (unsigned, 2 Byte)dword (unsigned, 4 Byte)qword(unsigned, 8 Byte)有符号类型有: int (signed, 2 Byte)long (signed, 4 Byte)int64(signed, 8 Byte)什…

Sharding-JDBC数据加密详解与实战

&#x1f680; ShardingSphere &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&…

进销存+小程序商城一体化,多门店管理解决方案-免费试用|亿发

为了适应市场变化和增强管理效率&#xff0c;越来越多的连锁&#xff0c;门店开始转向进销存小程序商城一体化&#xff0c;将进销存与订货商城结合&#xff0c;以实现更便捷、有效的经营模式&#xff0c;让企业迈向数字化时代。让我们一起来看看进销存小程序商城一体化系统相比…

掌握企业声音:企业新闻舆情查询API的重要作用与应用

摘要 在信息时代&#xff0c;企业的声誉和形象可以在瞬息万变的新闻舆情中受到影响。为了保护企业的声誉和形象&#xff0c;以及及时洞察市场动向&#xff0c;企业新闻舆情查询 API 应运而生。本文将探讨企业新闻舆情查询 API 的重要作用与应用&#xff0c;以及它在帮助企业实…

Linux输出内容到指定文件

1. 记录终端输出至文本文件 1.1 解决方案1&#xff1a;利用>和>>命令 区别&#xff1a; > 是把输出转向到指定的文件。注意&#xff1a;如文件已存在的话会重新写入&#xff0c;文件原内容不会保留。 >> 是把输出附加到文件的后面&#xff0c;文件原内容会…

车间生产线数据采集网关让生产透明化

**钡铼技术加工车间解决方案&#xff0c;通过把网关安装至一体电控箱控制生产设备&#xff0c;并与控制传输带的PLC结合&#xff0c;打造出了一个易部署、易维护、高可靠性&#xff0c;可24小时作业的自动化生产产线。 为什么采集数据&#xff1f;——实现生产透明化 1、数据…