多线程synchronized对象锁与静态锁之间的8锁问题理解

news2024/10/7 7:29:02

目录

    • 8锁问题
      • 锁1:多个线程使用同一对象分别调用不同带有带synchronized关键字且非静态的方法
      • 锁2:在锁1基础上,增加A线程执行的方法的执行时间,使得B有机会参与执行
      • 锁3:多个线程使用同一对象,一个线程执行带有对象锁的方法,一个线程执行普通方法
      • 锁4:多个线程使用不同对象分别调用不同带有对象锁的方法
      • 锁5:多个线程同一个对象分别调用对各自静态锁的方法
      • 锁6:多个线程同多个对象分别调用对各自静态锁的方法
      • 锁7:多个线程同一个对象分别调用对象锁的方法和静态锁的方法
      • 锁8:多个线程不同对象分别调用对象锁的方法和静态锁的方法

8锁问题

关注点有两个:锁的类型,锁的是谁
锁的类型:静态锁针对此类所有实例的对象,对象锁只针对当前对象
锁的是谁:对象锁锁的是此类中所有带synchronized关键字非静态的方法,静态锁锁的是此类所有带synchronized关键字且静态的方法
针对上面两点,这样在判断时要注意:是否是同一个对象,对象调用的方法是那种锁类型

锁1:多个线程使用同一对象分别调用不同带有带synchronized关键字且非静态的方法

分析:对象锁只针对当前对象,锁的是是所有带synchronized关键字且非静态的方法。

public class Application {
    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone.sendCall();},"B").start();
    }
   }
class Phone{
    synchronized void sendSMG(){
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
        System.out.println("打电话");
    }
}

结果:
在这里插入图片描述
思考1:为什么A线程与B线程之间启动要睡一会?
在代码中是顺序执行的,但线程的启动时操作系统能决定的,虽然A先进入就绪状态,但操作系统可能选择B先启动。让A线程与B线程启动时睡一会,可以确保一定是A线程先启动。因为操作系统处理是极快的,即使是1s的间隔,对于操作系统会有很大的时间差,是AB不在一起,让A极大的概率先启动。

思考2:为什么结果是这样?
两个关键点:
是同一个对象,锁的类型相同
A线程先启动,拿到对象锁,这时即使B线程启动了,但拿不到对象锁(A线程在没有执行完之前不会释放对象锁),调用不了带有synchronized对象锁的方法,只能进行等待。直到A线程执行完毕释放锁,B线程才能够获取锁继续去执行。

思考3:既然sendSMG()方法先执行,如果在方法中睡一会,sendCall()方法会不会先执行?
前面已经说到,A线程拿到锁后先执行sendSMG()方法,因为在方法中sleep()不会释放锁,即使执行时间过长,没有执行完毕,就不会释放锁,B就无法拿到锁执行带有synchronized对象锁的方法
思考4:如果Phone有一个普通方法,没有带synchronized锁,B线程启动后即使sendSMG()方法没有执行完毕,这个普通方法会被执行吗?
普通方法没有对象锁,B在执行时不用去等待A释放锁,因此只要B启动了就可以立即执行。如果A线程调用的也是这个普通方法,那么A,B两个线程可能同时在此方法内。

锁2:在锁1基础上,增加A线程执行的方法的执行时间,使得B有机会参与执行

验证上面的思考3,证明sendSMG()方法先执行并不是A线程先启动执行快,赶在了B线程调用sendCall()方法的问题,而是A不执行完sendSMG()方法释放对象锁,B根本不会有机会执行sendCall()方法。因为B线程一定后启动,使的对象锁被A先拿到。只要拿到锁后,一个对象内,多个线程只能有一个线程去执行带有synchronized对象锁的方法。

public class Application {

    public static void main(String[] args) throws InterruptedException {

        Phone phone = new Phone();
        new Thread(()->{phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone.sendCall();},"B").start();
    }
}

class Phone{
    synchronized void sendSMG(){
        try { TimeUnit.SECONDS.sleep(2); // 注意:我这里特意为2s使得这是B线程一定启动了 测试:B线程的sendCasll方法会不会先执行。} catch (InterruptedException e) {}
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
        System.out.println("打电话");
    }
}

代码只是在锁1的基础上增加了sendMsg()的执行时间。结果和锁1相同,先等待1s后,控制台出现"发送消息",然后紧接着出现"打电话"
在这里插入图片描述
思考: 这样会发生什么现象?
在这里插入图片描述
A线程抢到对象锁后,执行sendSMG()方法,在控制台输出"发送消息",然后睡1s,释放锁。B线程拿到锁,执行sendCall()方法,立即在控制台输出"打电话"

锁3:多个线程使用同一对象,一个线程执行带有对象锁的方法,一个线程执行普通方法

分析:对象锁,锁住的是带有synchronized的非静态方法,普通方法不再锁的范围
猜想:普通方法不受synchronized的影响,哪个线程执行的快,就可以先调用。

public class Application {

    public static void main(String[] args) throws InterruptedException {

        Phone phone = new Phone();
        new Thread(()->{phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone.sendHello();},"B").start();
    }
}

class Phone{
    synchronized void sendSMG(){
        try { TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {}
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
        System.out.println("打电话");
    }
    void sendHello(){
        System.out.println("hello");
    }
}

结果:
在这里插入图片描述
B线程的执行不需要等待A线程对象锁的释放,因为普通方法执行时根本不需要获取对象锁。

思考:如果A线程也调用普通方法,然后将普通方法改装成这样,会发生什么?
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述


以上使用的是同一个对象,探讨synchronized对象锁的问题,下面使用不同对象,探讨synchronized对象锁的问题


锁4:多个线程使用不同对象分别调用不同带有对象锁的方法

分析:对象锁:只针对当前对象有效,所以在不同对象间使用无效

public class Application {

    public static void main(String[] args) throws InterruptedException {

        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(()->{phone1.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone2.sendCall();},"B").start();
    }
}

class Phone{
    synchronized void sendSMG(){
        try { TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {}
        System.out.println("发送消息");
    }
    synchronized void sendCall(){
        System.out.println("打电话");
    }
    void sendHello(){
        System.out.println(Thread.currentThread().getName()+"进入");
        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { }
        System.out.println("hello");
        System.out.println(Thread.currentThread().getName()+"离开");
    }
}

结果:
在这里插入图片描述
思考:明明A线程先启动获取了对象锁,为什么B线程的方法在A线程没有执行完毕就开始执行?
关注点有两个:锁的类型,锁的是谁
在A,B线程使用的是不同对象,因此对于对象锁是无效的!B线程操作的对象有B线程自己的锁,A线程操作的对象有A线程自己的锁,二者不是同一个对象,因此锁不同。对于执行对象锁类型的方法,A线程的对象锁不能够锁住B线程的对象锁
思考:如果锁住不同对象的?
这时,就要使用类锁,因为不同对象也是由同一个类实例化出来的,可以使用类锁,生成一个不同对象也能识别的锁。


下面将引入静态锁


锁5:多个线程同一个对象分别调用对各自静态锁的方法

分析:静态锁,此类所有对象都有效。锁住的是带有synchronized的静态方法

public class Application {

    public static void main(String[] args) throws InterruptedException {
        Phone phone = new Phone();
        new Thread(()->{phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone.sendCall();},"B").start();
    }
}

class Phone{
     synchronized static void sendSMG(){

        try { TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {}
        System.out.println("发送消息");
    }
     synchronized static void sendCall(){
        System.out.println("打电话");
    }
}

效果:
在这里插入图片描述
方法都加上了static就相当于都是同一个类锁,不管是不是同一个对象,只要是此类实例化出的对象,在这个对象获取锁没有释放之前,任何对象都不能去执行带类锁的方法

锁6:多个线程同多个对象分别调用对各自静态锁的方法

效果和锁5相同,在都是类锁的方法上,不会区分是否是同一个对象。只要有一个对象在执行,不管是不是同一个对象,都只能等待去执行此类中带有类锁的方法。
思考:如果线程A使用对象1调用的是静态锁方法,线程B使用对象2调用的是普通方法,A先启动,那么对象2调用普通方法是需要等待A释放静态锁吗?
当然不会,因为普通方法根本没锁,类锁限制不了它


下面将静态锁与对象锁混合


锁7:多个线程同一个对象分别调用对象锁的方法和静态锁的方法

分析:有对象锁和静态锁,二者没有包含关系。
还是注意两个关键点:是否是同一个对象?是;调用的方法是否是相同锁类型?不是,一个是静态锁,一个是对象锁;
两个不同的方法,因为锁的类型不同,之间根本没有关系

public class Application {

    public static void main(String[] args) throws InterruptedException {

        Phone phone = new Phone();
        new Thread(()->{phone.sendSMG();},"A").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(()->{phone.sendCall();},"B").start();
    }
}

class Phone{
    synchronized void sendSMG(){

        try { TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {}
        System.out.println("发送消息");
    }
    static synchronized void sendCall(){
        System.out.println("打电话");
    }
}

效果:
在这里插入图片描述
A线程先执行,但A线程拿到的是对象锁,B线程启动后,拿到的是类锁,对象锁无法锁住类锁,因此B不必等待A执行完毕释放类锁后再去执行。

思考1:如果是两个线程调用的同一个方法加上静态锁呢?
这就和是否是同一个对象没有关系了,因为在静态方法上加锁是类级别的锁,不管是否是同一个对象,只要有一个线程拿到锁,在执行完毕释放锁之前,其他线程都不能执行此方法。但可以执行其他非静态锁方法。

思考2:如果A先拿到类锁,B后拿到对象锁,那B用等到A释放锁后再去执行吗?也就是说类锁与对象锁是否有包含关系?(不同对象)
在这里插入图片描述

证明:类锁与对象锁是作用范围不同的两种锁(对象锁只针对当前对象,类锁针对此类所有实例的对象),但不是类锁包含对象锁

锁8:多个线程不同对象分别调用对象锁的方法和静态锁的方法

和锁7思考2相同,线程A这个拿到的是属于这个对象1的对象锁,线程B拿到的是属于所有对象的类锁。二者调用方法的锁的类型不同,谁执行的快谁先输出,不存在等不等的问题。

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

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

相关文章

三菱Q系列QJ71C24N模块 MODBUS通信(含完整步骤+源代码)

MODBUS通信的其它相关基础知识请参看下面的文章链接: SMART S7-200PLC MODBUS通信_RXXW_Dor的博客-CSDN博客MODBUS 是 OSI 模型第 7 层上的应用层报文传输协议,它在连接至不同类型总线或网络的设备之间提供客户机/服务器通信。自从 1979 年出现工业串行链路的事实标准以来,…

7z压缩包有可能被破解吗,需要多久,暴力穷举和字典破解分别的速度分析

开门见山,我看到网上有很多此类软件,功能就是来破解7zip格式的压缩包,但都没有认真进行测试,这里认真进行判断和测试 首先,目前世界最快的计算机为Frontier,算力1,685.65 PFlop/s。目前最高的算力为全网比…

【IoT】智能小产品:简易电子琴设计

说明 随着电子技术的发展,电子技术正在逐渐改善着人们的学习、生活、工作,因此开发本系统希望能够给人们多带来一点生活上的乐趣,电子技术与音乐的结合不断加深。 由此而产生的电子琴在这种形势下,因其体积小,易于携…

芯科EFRBG22C112 empty工程创建

目录 1.使用工具 2.创建工程 2.1进入welcome,选择芯片,点击start ​编辑 2.2选择sdk4.2.0版本 2.3点击Create New Project 2.4同步步骤创建引导程序bootloader-apploader 3.遇到问题 1.使用工具 ARM仿真器 EFR32BG22C112芯片开发板 pc 使用ARM仿真器连接BG22…

PMP考试多少分算通过?

PMP 是没有具体分数的,只有等级, PASS 就是通过了这张成绩单就是 PASS,3A。主要看头部这里,PASS 就是通过了,FAIL 就是没通过。至于说的 3A,2A1T 啥的,是对应的每个模块的成绩,PMP 的…

【leetcode - 基础】编程能力( 4 / 20天 )

目录 Day - 1 896. 单调数列 - 简单ac 28. 找出字符串中第一个匹配项的下标 - KMP 1、kmp模板 2、java api Day - 2 110. 平衡二叉树 - 递归 1、自顶向下 - 暴力 459. 重复的子字符串 - 暴力 Day - 3 150. 逆波兰表达式求值 - 栈 后缀表达式 66.加一 - 模拟 Day…

Tensorflow 基础与实战

目录 一、线性回归实现 1.1 数据加载与查看绘图 1.2 模型建立、训练与预测 二、神经网络实现 2.1 数据加载与查看绘图 2.2 模型建立、训练与预测 三、逻辑回归实现 3.1 数据加载与查看绘图 3.2 模型建立、训练与预测 四、softmax分类 4.1 数据加载 4.2 数据归一化 …

ReadyAPI x64bit 3.43.0 Crack

ReadyAPI 允许团队在一个集中的界面中创建、管理和执行自动化的功能、安全和性能测试——为敏捷和 DevOps 软件团队提高 API 质量。 ReadyAPI 在单一平台上提供三个模块: 在ReadyAPI 测试模块中,您创建功能测试以验证您的服务是否按预期工作。您可以使用…

高频数组算法

1.二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输…

程序员的职业生涯个人规划(附上学习资料)

目录 前言 1.程序员的规划 2.程序员的进化路径 3.IT行业的难度 4.你的选择 5.再谈谈资本、工具人和内卷 总结: 前言 今天不讲技术也不讲干货,来聊一聊程序员职业生涯的个人规划。希望对不管是想入门的还是已经在这条路上的朋友能有一个帮助。 1.程…

opencv之直方图绘制及均衡化

直方图均衡化优势:增强图像对比度,使对比度较低的局部区域获得高对比度。当图像非常暗或者非常亮,并且背景和前景之间的差异非常小时,此方法非常有效,能够解决暴露过度或暴露不足的问题。直方图均衡化缺陷:…

多彩的书写工具,画图写字更好看,米家液晶小黑板多彩版上手

平时临时记些信息,或者是教小朋友认字的时候,液晶小黑板都是特别实用的工具,我之前就用过米家液晶小黑板,最近我发现米家新出了一款彩色笔迹的小黑板,书写效果更加好看,比以前单色款的更好用。 这款米家液晶…

【技术分享】MA21日均线交易策略

文章目录1.前言1.1.相关术语1.2.MA均线系统设置分类1.3.斐波那契数列2.MA21日均线2.1.MA21日均线2.2.MA21日均线交易策略2.3.MA21日均线案例分析1.前言 1.1.相关术语 空头市场(Bear Market):亦称熊市,指价格长期呈 下跌 趋势的证…

操作系统权限提升(十)之系统错误配置-计划任务提权

系列文章 操作系统权限提升(一)之操作系统权限介绍 操作系统权限提升(二)之常见提权的环境介绍 操作系统权限提升(三)之Windows系统内核溢出漏洞提权 操作系统权限提升(四)之系统错误配置-Tusted Service Paths提权 操作系统权限提升(五)之系统错误配置-PATH环境变量提权 操作…

VUE3.0学习

一、父子传值 父组件向子组件传值和vue2.0相比区别不大&#xff0c;区别在于api的使用&#xff0c;让接收参数的写法多样化。父组件::::: <template><div class"about"><div><main><TheWelcome :info"parMsg"/></main>…

【react】理解Fiber

FiberFiber概念结构Fiber 树的遍历是这样发生的【深度遍历】。window.requestIdleCallback()requestAnimationFrameFiber 是如何工作的结论有react fiber&#xff0c;为什么不需要vue fiberFiber 概念 JavaScript引擎和页面渲染引擎两个线程是互斥的&#xff0c;当其中一个线…

12月 被大厂以“人员优化”的名义 无情的辞退了...

前几天&#xff0c;一个认识了好几年在大厂工作的测试员朋友&#xff0c;年近30了&#xff0c;却被大厂以“人员优化”的名义无情被辞&#xff0c;据他说&#xff0c;有一个月散伙饭都吃了好几顿…… 在很多企业&#xff0c;都有KPI考核&#xff0c;然后在此基础上还会弄个“…

IB EE 学习干货,从选学科/课题/写稿/对稿/交稿几个方面入手分享

本文从选学科&#xff0c;选课题&#xff0c;写稿&#xff0c;对稿&#xff0c;交稿几个方面入手分享。关于不同学科的EE&#xff0c;本文涵盖了数学和物理EE&#xff08;因为我们猜很多同学们都选了这两个学科的EE&#xff09;。 文中分享的学习方法都是我们从个人经历出发&am…

微服务 @SentinelResource 服务网关

微服务 SentinelResource 服务网关SentinelResourceFeign整合Sentinel什么场景下需要Feign集合Sentinel呢&#xff1f;服务网关为什么需要网关网关组件Gateway快速入门什么是Gateway操作示例自定义路由规则SentinelResource 自定义异常返回是对所有的情况进行统一处理&#xf…

DTC补货实战:从算法到落地

本文作者&#xff1a;凡飞&#xff0c;从快递到快消&#xff0c;一个平凡的供应链算法深耕者。“ 我希望衡量我们ai团队价值的&#xff0c;不是创造了多么精深的算法&#xff0c;而是跨越算法到落地间距离的能力。”近年来随着电商行业从增量市场逐步成长到了存量市场&#xff…