记录一 :对象锁和类锁

news2025/3/11 9:29:11

目录

简介

通过8个案例来解释说明

案例及总结


简介

阿里规约【强制】高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能 锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁

说明:尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用 RPC 方法。

通过8个案例来解释说明

  1. 标准访问有a、b两个线程,先打印结果email还是sms
  2. sendEmail 方法中加入暂停3秒钟,先打印结果 email还是sms
  3. 添加一个普通的hello方法,先打印结果 email还是hello
  4. 有两部手机,先打印结果 email还是sms
  5. 有两个静态同步方法,有1部手机,先打印结果 email还是sms
  6. 有两个静态同步方法,有2部手机,先打印结果 email还是sms
  7. 有1个静态同步方法,有一个普通同步方法,有1部手机,先打印结果 email还是sms
  8. 有1个静态同步方法,有一个普通同步方法,有2部手机,先打印结果 email还是sms

案例及总结

1.标准访问有a、b两个线程,先打印结果email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public synchronized void sendEmail(){
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            phone.sendSms();
        },"b").start();
    }
}
//结果:
--------sendEmail
--------sendSms

Process finished with exit code 0

2.sendEmail 方法中加入暂停3秒钟,先打印结果 email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            phone.sendSms();
        },"b").start();
    }
}
//结果:
--------sendEmail
--------sendSms

Process finished with exit code 0

总结 1-2:一个对象里面如果有多个synchronized方法,某一个时刻内,只要有一个线程去调用其中的一个synchronized方法了,其他线程都只能等待,换句话说,某一时刻内,只能有唯一的一个线程去访问这些synchronized方法,锁的是当前的对象this,被锁后,其他的线程都不能进入当前对象的其他的synchroniezd方法。

3.添加一个普通的hello方法,先打印结果 email还是hello

import java.util.concurrent.TimeUnit;

class Phone{
    public synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            //phone.sendSms();
            phone.hello();
        },"b").start();
    }
}
//结果:
-------hello
--------sendEmail

Process finished with exit code 0

4.有两部手机,先打印结果 email还是sms 

import java.util.concurrent.TimeUnit;

class Phone{
    public synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            //phone.sendSms();
           // phone.hello();
            phone2.sendSms();
        },"b").start();
    }
}
//结果
--------sendSms
--------sendEmail

Process finished with exit code 0

总结 3-4:加个普通的方法后发现和同步锁无关  不存在资源争抢的问题
        换成两个对象后,不是同一把锁(phone1,phone2)了,不存在资源争抢的问题

 5.有两个静态同步方法,有1部手机,先打印结果 email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public static synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public static synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
       // Phone phone2 = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            phone.sendSms();
           // phone.hello();
           // phone2.sendSms();
        },"b").start();
    }
}
//结果
--------sendEmail
--------sendSms

Process finished with exit code 0

 6.有两个静态同步方法,有2部手机,先打印结果 email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public static synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public static synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
           // phone.sendSms();
           // phone.hello();
           phone2.sendSms();
        },"b").start();
    }
}
//结果
--------sendEmail
--------sendSms

Process finished with exit code 0

总结 5-6:都换成静态同步方法后,情况又变化,
三种synchronized锁的内容有一些差别
对于普通同步方法:锁的是当前的实例对象,通常是指this,具体的一部手机,所有的普通同步方法用的都是同一把锁 -->实例对象本身
对于静态同步方法:锁的是当前类的class对象,如phone.class唯一的一个模版
对于同步方法块:锁的是synchronized括号内的对象

7.有1个静态同步方法,有一个普通同步方法,有1部手机,先打印结果 email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public static synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
            phone.sendSms();
           // phone.hello();
          // phone2.sendSms();
        },"b").start();
    }
}
//结果
--------sendSms
--------sendEmail

Process finished with exit code 0

8.有1个静态同步方法,有一个普通同步方法,有2部手机,先打印结果 email还是sms

import java.util.concurrent.TimeUnit;

class Phone{
    public static synchronized void sendEmail(){
        try { TimeUnit.MILLISECONDS.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}
        System.out.println("--------sendEmail");
    }

    public synchronized void sendSms(){
        System.out.println("--------sendSms");
    }
    public void hello(){
        System.out.println("-------hello");
    }
}
public class LockTest {

    public static void main(String[] args) {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() ->{
            phone.sendEmail();
        },"a").start();
        //暂停毫秒 保证a线程先启动
        try { TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
        new Thread(() ->{
           // phone.sendSms();
           // phone.hello();
           phone2.sendSms();
        },"b").start();
    }
}
//结果
--------sendSms
--------sendEmail

Process finished with exit code 0

总结 7-8:当一个线程试图访问同步代码时,它必须得到锁,正常退出或抛出异常必须释放锁。
        1.所有的同步普通同步方法用的都是同一把锁-->实例对象本身,就是new出来的具体实例对象本身,本类this。也就是说如果一个实例对象的普通同步方法获取锁后,该实例对象的其他同步方法必须等待获取锁的方法释放锁后才能获取锁。
       2.所有的静态同步方法用的也是同一把锁-->类对象本身,就是我们所说的唯一模板class,
具体实例对象this和唯一模版class,这两把锁是两个不同的对象,所以静态同步方法与普通同步方法之间是不会竞态条件的。
       3.但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁 。

如果还是没有整明白类锁和对象锁 一图解千愁

简单说下:程序中Phone phone1 = new Phone();phone1是在堆区 ,就是对象锁在的地方

Phone Class类模板是在方法区,所以说对象锁和类锁两个不同的对象,不存在竞太的关系。

如有不对的地方欢迎留言指正

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

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

相关文章

提高工作效率的宝藏网站和宝藏工具

一、好用的网站 面包多 面包多 创作者在面包多,通过出售课程,文章,绘画,创意作品,软件,电子书,音乐, 游戏,咨询服务,每月获得 数百万元 收入。 写作素材模板…

二阶段算法:R-CNN类网络

博主简介 博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的&#xff0c…

【Java 数据结构】ArrayList的实现和底层源码讲解

🎉🎉🎉点进来你就是我的人了 博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!人生格言:当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔🦾&am…

java day9

第九章 使用swing 9.1 创建应用程序9.1.1 创建页面9.1.2 开发框架9.1.3 创建组件&& 9.1.4 将组件加入到容器中 9.2 使用组件9.2.1 图标9.2.2 标签9.2.3 文本框9.2.4 文本区域9.2.5 可滚动窗格9.2.6 复选框和单选按钮9.2.7 组合框9.2.8 列表 9.1 创建应用程序 import j…

FPGA基于SFP光口实现10G万兆网UDP通信 10G Ethernet Subsystem替代网络PHY芯片 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案4、vivado工程详解5、上板调试验证并演示6、福利:工程代码的获取 1、前言 目前网上的fpga实现udp基本生态如下: 1:verilog编写的udp收发器,但不带ping功能,这样的代…

The GNU nano text editor (文本编辑器)

The GNU nano text editor (文本编辑器) https://www.nano-editor.org/ GNU nano is a small and friendly text editor. 1 GNU nano The GNU nano text editor https://www.nano-editor.org/dist/latest/nano.html Source Code https://git.savannah.gnu.org/cgit/nano.gi…

EIGRP 配置,详解拓扑表,路由汇聚

1.3 EIGRP 拓扑,路由以及汇聚 1.3.1 实验目的 通过对 EIGRP 拓扑,路由以及汇聚相关实验的练习,掌握 EIGRP 建立拓扑信息的方式, 度量计算方法,如何调整度量,非等价负载均衡,以及 EIGRP 末节路…

anaconda ( jupyter notebook ) 安装 Cartopy库

文章目录 一、Cartopy库是什么?二、一步到位安装(装不上的话用下面那个方法虚拟环境安装)三、如何在anaconda ( jupyter notebook ) 虚拟环境安装 Cartopy库? 一、Cartopy库是什么? Cartopy 是一个开源免费的第三方 P…

mac压缩文件多了__MACOSX目录问题

文章目录 背景原因解决方案:更换压缩方式分析问题拓展(.DS_Store) 背景 项目中有一个场景,需要把目录压缩为app离线包的zip 但是压缩之后一致打不开,别人上传的zip是好的 原因 如图,我上传的在安卓设备…

D.8零样本文本分类应用:基于UTC的医疗意图分类,打通数据标注-模型训练-模型调优-预测部署全流程。

NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型压缩算法等 专栏详细介绍:NLP专栏简介:数据增强、智能标注、意图识别算法|多分类算法、文本信息抽取、多模态信息抽取、可解释性分析、性能调优、模型…

如何制作 ChatGPT 清晰有效咒语与Chat GPT高效交流——基础篇 第二课

在上一篇文章中,我们已经了解了 ChatGPT 的特性、应用范围以及逆天之处。然而,要想获得 ChatGPT 的逆天能力,最关键的一点就是必须掌握准确的“咒语”,即让其能够准确地理解我们所说的话,以及我们想要的东西。本篇文章…

一条记录的多幅面孔-事务的隔离级别与 MVCC

一、事务隔离级别 引出:**事务的隔离性要求,**理论上在某个事务对某个数据进行访问时,其他事务应该进行排队,当该事务提交之后,其他事务才可以继续访问这个数据。我们既想保持事务的 隔离性 ,又想让服务器…

CCED,落下帷幕,国产新型编辑技术的锋芒,终于露出来了

大家还记得在DOS时代,你们常用的办公软件有哪些吗? 想必一定少不了朱崇君的CCED和求伯君的WPS吧,前者是字表处理,后者是文字处理。在DOS时代,这两个软件用起来真的是得心应手啊。 而这个时代,也成为了CCE…

jupyter中的魔法函数

在jupyter中,使用魔法函数可以简单的实现一些单纯python要很麻烦才能实现的功能。 1. % 行魔法函数,只对本行代码生效。 2. %% Cell魔法函数,在整个Cell中生效,必须放于Cell首行。 3. %lsmagic: 列出所有的魔法函数 4…

Android Gradle —— flavorDimensions 与 productFlavors

参考: Android Gradle(3)— FlavorDimensions_积跬步_图腾的博客-CSDN博客 flavorDimensions和productFlavors——安卓gradle_猛猛的小盆友的博客-CSDN博客 多维度打包的介绍 flavorDimensions 从单词字面理解知道是 “风味维度”&#xf…

jsp小练习01--jdbc小练习01

目录 jsp小练习01 jdbc小练习01 设计数据库 以下是一个基本的登录页面(login.jsp): 以下是checklogin.jsp页面的示例代码: 以下是main.jsp页面的示例代码: 以下是add.jsp页面的示例代码: 以下是doa…

【2023 · CANN训练营第一季】昇腾AI入门课(Pytorch)——第三章 AI应用开发

第1节 课程概述 第1单元 本课程是否适合您 1.没有深度学习的背景 边学习边补充基础 2.少量深度学习背景,但并不了解华为昇腾 对于昇腾的学习是贯穿全程的 3.听说过或接触过华为昇腾,但不知道如何基于昇腾使能AI应用。 保持学习,按时交作业…

Letcode 两数之和

1. 两数之和 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以…

Wi-Fi 6(802.11ax)解析12:下行OFDMA接入机制(DL-OFDMA)

序言 在介绍完802.11ax的信道接入以及其触发帧机制后,本文着重介绍下行OFDMA的接入机制(即DL-OFDMA) 下行OFDMA接入机制(DL-OFDMA) OFDMA是一种多用户通信机制,其只适用于802.11ax AP和802.11ax用户之间…

ChatGPT 学习 ES lucene 底层写入原理,源码

一直有个疑问“学习最新版lucene 数据写入相关的源码,应该看哪些源码,以什么顺序看(先看什么,后看什么)?” 对于Lucene的数据写入过程,可以分为以下几个阶段 在学习Lucene的数据写入相关的源码…