java线程锁synchronized的几种情况

一、对象方法锁

1、成员方法加锁

         同一个对象成员方法有3个synchronized修饰的方法,通过睡眠模拟业务操作

    public class   CaseOne {

        public   synchronized   void  m1(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m1");
        }

        public   synchronized   void  m2()  {
            try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m2");
        }

        public   synchronized   void  m3()  {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m3");
        }
    }
    private final static SimpleDateFormat  SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private final static ExecutorService POOL = Executors.newFixedThreadPool(4);

    public static void main(String[] args) {
        CaseOne caseOne = new CaseOne();
        System.out.println(SDF.format(new Date())+"------------>start");
        POOL.execute(caseOne::m1);
        POOL.execute(caseOne::m2);
        POOL.execute(caseOne::m3);
    }

        运行结果:

        通过运行结果可以看出,三个业务方法,执行完成总共花费了6s,虽然使用了多线程,这三三个方法其实是串行作业的,因此可得出一下结论:   

        同一个对象的不同方法加synchronized修饰,只要其中一个方法抢到锁,其他被synchronized修饰的方法都互斥,本质是对象上锁。

2、成员方法不加锁

    public class   CaseTwo {

        public   synchronized   void  m1(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m1");
        }

        public    void  m2()  {
            try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m2");
        }

        public   synchronized   void  m3()  {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+"------------>m3");
        }
    }
        CaseTwo caseTwo = new CaseTwo();
        System.out.println(SDF.format(new Date())+"------------>start");
        POOL.execute(caseTwo::m1);
        POOL.execute(caseTwo::m2);
        POOL.execute(caseTwo::m3);

          运行结果:

      三个业务方法执行完成总共花费了4s,结合第一个案例可以得出以下结论:

      同一个对象的不同方法加synchronized,其中加锁方法和不加锁的成员方法没有竞争关系,不产生互斥。

3、不同对象方法锁

        案例1和案例2研究的是同一个的对象,加锁和不加锁的情况,下面来研究不同对象的情况。

    public static class   CaseThree {

        private final String   name;

        public CaseThree(String name) {
            this.name = name;
        }

        public   synchronized   void  m1(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+this.name +"------------>m1");
        }
    }
        CaseThree caseThree1 = new CaseThree("caseThree1");
        CaseThree caseThree2 = new CaseThree("caseThree2");
        System.out.println(SDF.format(new Date())+" "+"------------>start");
        POOL.execute(caseThree1::m1);
        POOL.execute(caseThree2::m1);

         运行结果:

      由执行结果可以看出,对象caseThree1 和对象caseThree12调用同一个方法,同时执行完成,可以得出以下结论:

       不同的对象执行同一个成员方法,没有竞争关系,加锁方法不互斥。

二、类方法加锁

         下面研究一下一个类型static修饰的静态方法加锁

1、静态方法锁

    public static class   CaseFour {

        public  static synchronized   void  m1(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+"------------>m1");
        }

        public  static synchronized   void  m2(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+"------------>m2");
        }
    }
    
        System.out.println(SDF.format(new Date())+" "+"------------>start");
        POOL.execute(CaseFour::m1);
        POOL.execute(CaseFour::m2);

  

           由执行的结果可以得出以下结论:

           同一个类的不同静态方法之间存在竞争关系,先抢到锁的先执行。

2、不同对象静态方法锁

    public static class   CaseFive {

        public  static synchronized   void  m1(String name){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+name+"------------>m1");
        }
    }
        CaseFive caseFive1 = new CaseFive();
        CaseFive caseFive2 = new CaseFive();
        System.out.println(SDF.format(new Date())+" "+"------------>start");
        POOL.execute(()->caseFive1.m1("caseFive1"));
        POOL.execute(()->caseFive2.m1("caseFive2"));

         由运行结果可以得到以下结论:

         同一个类的不同对象调用同一个静态方法,存在竞争关系,会产生互斥。

3、类方法锁和成员方法锁

   ◆场景一:

    public static class   CaseSix {

        public  static synchronized   void  m1(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+"------------>m1");
        }

        public  synchronized   void  m2(){
            try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
            System.out.println(SDF.format(new Date())+  " "+"------------>m2");
        }

    }
      CaseSix caseSix = new CaseSix();
      System.out.println(SDF.format(new Date())+" "+"------------>start");
      POOL.execute(()->caseSix.m1());
      POOL.execute(()->caseSix.m2());

        由执行结果可得出以下结论:

   

       同一个类的静态方法和成员方法加锁,同一个对象同时调用,会场生竞争关系,先抢到锁的先执行。

  ◆场景二:

       CaseSix caseSix1 = new CaseSix();
       CaseSix caseSix2 = new CaseSix();
       System.out.println(SDF.format(new Date())+" "+"------------>start");
       POOL.execute(()->caseSix1.m1());
       POOL.execute(()->caseSix2.m2());

   

         由运行结果可知:

        同一个类的不同对象,分别调用静态类和成员方法,不产生竞态关系。

三、线程锁总结

        通过查看反编译字节码(javap   -v  CaseOne.class),可以看到synchronized加锁机制是通过monitorenter加锁,通过

monitorexit自动释放锁。

          对象普通成员方法是通过ACC_SYNCHRONIZED标记加锁

         类方法加锁是通过, ACC_STATIC, ACC_SYNCHRONIZED进行标记的

       类方法是在类加载过程中已经打上标记了,类信息存储在jvm的常量池中,而对象的方法锁是在运行动态确定的,因此类方法锁和不同的对象成员方法锁之间不存在竞争关系。在并发情景,能用无锁的数据块就不要用锁,能锁区块,就不要锁整个方法体,能锁对象就不要用类锁,代码块锁、方法锁、类锁的锁粒度是主次增大的。

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

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

相关文章

【机器学习】朴素贝叶斯算法详解与实战扩展

欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 引言 朴素贝叶斯算法是一种基于概率统计的分类方法,它利用贝叶斯定理和特征条件独立假设来预测样本的类别。尽管其假设特征之间相互独立在现实中往往不成立,但朴素贝叶斯分类器因其计算…

vscode单独设置项目的字符集

vscode有个默认的字符集,直接修改这里的话将会修改整个vscode工具的字符集。如果不同的项目使用不同的字符集,就不能修改这个默认的设置了。而是需要针对每个项目进行修改。 修改方法: 使用shiftctrlp进入settings的菜单页面,点击…

Leetcode—236. 二叉树的最近公共祖先【中等】

2024每日刷题(142) Leetcode—236. 二叉树的最近公共祖先 实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL…

怎么把便签主面板置顶 便签主面板置顶方法

作为一名经常需要处理大量信息和任务的作家,我发现便签记事真的是我的救星。无论是临时灵感、会议要点还是待办事项,便签都能帮我快速记录,让我不再遗漏任何重要信息。而且,便签的应用场景也非常广泛,无论是在电脑前写…

王道计算机数据结构+插入排序、冒泡排序、希尔排序、快速排序、简单选择排序

本内容是基于王道计算机数据结构的插入排序、冒泡排序、希尔排序、快速排序、简单选择排序整理。 文章目录 插入排序算法性能代码 冒泡排序算法性能代码 希尔排序算法性能代码 快速排序算法性能代码 简单选择排序算法性能代码 插入排序 算法 算法思想:每次将一个…

LLM代理应用实战:构建Plotly数据可视化代理

如果你尝试过像ChatGPT这样的LLM,就会知道它们几乎可以为任何语言或包生成代码。但是仅仅依靠LLM是有局限的。对于数据可视化的问题我们需要提供一下的内容 描述数据:模型本身并不知道数据集的细节,比如列名和行细节。手动提供这些信息可能很麻烦&#…

zigbee笔记:七、zigbee系统电源管理与睡眠唤醒

zigbee的低功耗、近距离无线传输的特点使得其在一众近距离无线传输方案中备受青睐。而zigbee低功耗优势是通过根据不同工况选择运行在不同的运行模式(供电模式)实现的,因此,掌握zigbee的系统电源管理与睡眠唤醒的相关知识&#xf…

发挥储能系统领域优势,海博思创坚定不移推动能源消费革命

随着新发展理念的深入贯彻,我国正全面落实“双碳”目标任务,通过积极转变能源消费方式,大幅提升能源利用效率,实现了以年均约3.3%的能源消费增长支撑了年均超过6%的国民经济增长。这一成就的背后,是我国能源结构的持续…

c#调用c++ dll库报错System.BadImageFormatException

System.BadImageFormatException:“试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)” 1. dll需要选择release模式进行编译 2.选择相同位数,比如x64平台,c#也需要x64 3.不要设置c#不支持的函数供调用 比如: c可以输出到控制台…

昇思学习打卡-16-热门LLM及其他AI应用/K近邻算法实现红酒聚类

文章目录 算法原理距离定义模型构建 算法原理 K近邻算法可以用在分类问题和回归问题上,它的原理如下:要确定一个样本的类别,可以计算它与所有训练样本的距离,然后找出和该样本最接近的k个样本,统计出这些样本的类别并…

中职综合布线实训室

一、中职综合布线实训室建设背景 在数字化转型的大潮中,计算机网络技术作为支撑数字中国建设的基石,其重要性不言而喻。面对汹涌而来的数字时代,中等职业学校(简称中职)作为技术技能型人才培养的重要基地,…

如何使用Vger对已经过身份验证的Jupyter实例进行安全检测

关于Vger Vger是一款功能强大的交互式命令行应用程序,广大研究人员可以利用Vger与已经过身验证的Jupyter实例进行交互,并对其执行人工智能或机器学习方面的安全检测操作。 使用场景 1、作为红队研究人员,当我们寻找到了Jupyter凭证之后&…

单例模式的简单理解

单例模式 前言一、单例模式是什么二、单例模式的使用饿汉模式单线程下的懒汉模式多线程下的懒汉模式(优化懒汉模式)加锁 三、总结 前言 设计模式是将一些经典的问题场景进行整合归纳,并提供一些解决方案,相当于一种“套路”。 熟…

政企单位光纤资源高效管理与优化策略

引言 随着信息技术的飞速发展,政企单位对于通信基础设施的管理要求日益提高。然而,传统的管理模式,如Excel表格记录和纸质审批流程,已难以满足当前复杂多变的业务需求。在此背景下,我们实施了光纤管理的数字化转型项目…

LLMs的基本组成:向量、Tokens和嵌入

编者按:随着人工智能技术的不断发展,大模型(语言、视觉,或多模态模型)已成为当今AI应用的核心组成部分。这些模型具有处理和理解自然语言等模态输入的能力,推动了诸如聊天机器人、智能助手、自动文本生成等…

防火墙安全策略练习

实验拓扑 实验要求 1.DMZ区内的服务器,办公区仅能在办公时间内(9:00 — 18:00)可以访问,生产区的设备全天可以访问 2.生产区不允许访问互联网,办公区和游客区允许访问互联网 3.办公区设备10.…

C++初学者指南-5.标准库(第一部分)--顺序视图

C初学者指南-5.标准库(第一部分)–顺序视图 文章目录 C初学者指南-5.标准库(第一部分)--顺序视图std::string_view (C17)避免不必要的内存分配类似字符串的函数参数创建string_viewsstring_view接口 std::span (C20)作为参数(主要用例&#x…

笔记本硬盘数据恢复的6种方法!简单易懂

可以从笔记本电脑硬盘恢复已删除的数据吗? “我不小心删除了笔记本电脑硬盘上的重要数据。请问我可以在笔记本电脑硬盘上恢复已删除的数据吗?如果可以,我应该怎么做才能恢复数据呢?” 很多笔记本电脑用户可能会不小心地从电脑中…

翻译|解开LLMs的神秘面纱:他们怎么能做没有受过训练的事情?

大语言模型(LLMs)通过将深度学习技术与强大的计算资源结合起来,正在彻底改变我们与软件互动的方式。 虽然这项技术令人兴奋,但许多人也担忧LLMs可能生成虚假的、过时的或有问题的信息,他们有时甚至会产生令人信服的幻…

顶顶通呼叫中心中间件-打电话没声音检查步骤(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-电话没声音检查步骤(mod_cti基于FreeSWITH) 检查步骤 1、检查配置文件 检查配置文件:打开ccadmin -> 配置文件 -> vars -> external_ip$${local_ip_v4}看一下这个有没有配置正确的外网IP,如果没有配置正确就需要配置正…