线程“八锁“ synchronized到底是对哪个对象加锁?

news2024/11/29 22:37:09

线程"八锁" synchronized到底是对哪个对象加锁?

习题一

class Number{
    public synchronized void a(){
        System.out.println("1");
    }

    public synchronized void b(){
        System.out.println("2");
    }
}
public class TestBlock {
    public static void main(String[] args) throws InterruptedException {
        Number n = new Number();
        Thread t1 = new Thread(()->{
            System.out.println("t1->begin!!!");
            n.a();
        });

        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n.b();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

对于Number类里面的a方法和b方法都是对当前对象this加锁,也就是对Number对象加锁.

当两个线程通过对象调用两个方法(a和b)的时候,会产生互斥效果-->锁的都是同一个对象(Number对象)

对于打印结果取决于任务调度器先调度谁就先打印谁,两者都有机会被优先调度,所以打印顺序可能是 1 2 也可能是2 1.

习题二

class Number1{
    public synchronized void a(){
        System.out.println("1");
    }

    public synchronized void b(){
        System.out.println("2");
    }
}
public class TestBlock1 {
    public static void main(String[] args) throws InterruptedException {
        Number1 n = new Number1();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1->begin!!!");
            n.a();
        });

        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n.b();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

对比习题1就相当于在t1线程里面多加了个sleep,让其t1线程睡眠一会.

但是,t1线程和t2线程锁的还是同一个对象Number具有互斥效果.

打印结果还是取决于任务调度器的调度,如果先调度的是t1(t1先拿到锁),那么就等待1s后,执行a方法打印1,然后线程2在执行b方法,打印2.

还有一种情况是任务调度器先调度t2线程,就会先打印2,然后睡眠1s后打印1.

习题3

class Number3{
    public synchronized void a(){
        System.out.println("1");
    }
    public synchronized void b(){
        System.out.println("2");
    }
    public void c(){//没有加锁
        System.out.println("3");
    }
}
public class TestBlock3 {
    public static void main(String[] args) throws InterruptedException {
        Number3 n = new Number3();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1->begin!!!");
            n.a();
        });
        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n.b();
        });
        Thread t3 = new Thread(()->{
            System.out.println("t3->begin!!!");
            n.c();
        });
        t1.start();
        t2.start();
        t3.start();
        t1.join();
        t2.join(); 
        t3.join();
    }
}

习题3是多加了一个方法c,但是方法c没有加synchronized.

对于这个题,方法a,b都加了synchronized可以其互斥效果,但是反方c没有加synchronized,不会被加锁.也就是线程1或者线程2执行,线程3不会阻塞,依然会继续往后执行.

对于打印结果还是取决于任务调度器的调度.

如果先调度的是线程1,那么会等待1s后打印1,但是方法c没有加锁,所以不会阻塞,线程3执行方法c打印3,然后1s后打印1 ,线程1释放锁之后唤醒线程2,线程2执行b方法打印2.====> 3 一秒后 1 2

由于线程2和线程3是并发执行的取决于任务调度器

如果先调度的是线程2,那么会先打印 2 ,然后线程3并发/并行的执行方法c打印3,然后一秒后打印1

===> 2 3 一秒后 1

如果先调度的是线程3,那么会先打印 3 ,然后线程2并发/并行的执行方法b打印2,然后一秒后打印1

===> 3 2 一秒后 1

习题4

class Number4{
    public synchronized void a(){
        System.out.println("1");
    }
    public synchronized void b(){
        System.out.println("2");
    }
}
public class TestBlock4 {
    public static void main(String[] args) throws InterruptedException {
        Number4 n1 = new Number4();
        Number4 n2 = new Number4();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1->begin!!!");
            n1.a();
        });
        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n2.b();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

这个题有两个对象n1和n2.

有两个对象,n1.a(),n2.b(),既然是不同的对象,也就是线程1和线程2对不同的对象加锁=>锁的不是同一个对象不产生互斥效果,并发/并行的执行,但由于t1线程睡眠1s钟,所以总是先打印2 一秒后 在打印1

习题5

class Number5{
    public synchronized static void a(){
        System.out.println("1");
    }
    public synchronized void b(){
        System.out.println("2");
    }
}
public class TestBlock5 {
    public static void main(String[] args) throws InterruptedException {
        Number5 n = new Number5();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1->begin!!!");
            n.a();
        });
        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n.b();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

线程1调用a方法,a是静态方法,对静态方法加锁相当于是对类对象加锁-->锁的是Number类对象

线程2调用b方法,b是非静态方法,相当于对this对象加锁->也就是n对象

所以锁的是不同的对象==>对不同的对象进行加锁--->不会产生互斥效果

所以两线程是并发执行的,由于睡眠,先打印2,一秒后打印1

习题6

class Number6 {
    public synchronized static void a(){
        System.out.println("1");
    }
    public synchronized static void b(){
        System.out.println("2");
    }
}
public class TestBlock6 {
    public static void main(String[] args) throws InterruptedException {
        Number6 n = new Number6();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1->begin!!!");
            n.a();
        });
        Thread t2 = new Thread(()->{
            System.out.println("t2->begin!!!");
            n.b();
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

两个线程调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.

取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1

习题7

class Number7 {
    public synchronized static void a(){
        System.out.println("1");
    }
    public synchronized  void b(){
        System.out.println("2");
    }
}
public class TestBlock7 {
    public static void main(String[] args) {
        Number7 n1 = new Number7();
        Number7 n2 = new Number7();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            n1.a();
        });
        Thread t2 = new Thread(()->{
            n2.b();
        });
        t1.start();
        t2.start();
    }
}

加锁的对象不一样,线程1调用的方法对类对象加锁,线程2里面利用n2对象调用b方法,对n2对象加锁,所以两个线程是对不同的对象进行加锁->不产生互斥效果.

所以线程1和线程2是并发执行的,所以是先打印2,一秒后打印1

习题8

class Number8{
    public static synchronized void a() {
        System.out.println("1");
    }
    public static synchronized void b() {
        System.out.println("2");
    }
}
public class TestBlock8 {

    public static void main(String[] args) {
        Number8 n1 = new Number8();
        Number8 n2 = new Number8();
        Thread t1 = new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            n1.a();
        });
        Thread t2 = new Thread(()->{
            n2.b();
        });
        t1.start();
        t2.start();
    }
}

虽然是不同的对象调用方法

但是调用的方法都是对静态方法进行加锁==>都是对类对象加锁-->锁的是相同对象-->产生互斥效果.

取决于任务调度器. 先调度线程1就是 1s之后打印1 ,然后打印2,否则的话先调度线程2就是 打印2 ,1s之后然后打印1

总结

分析这种问题,首先往最根头看起,到底锁的对象是谁,是this还是类对象,还是没有加锁,然后在确定多个对象是否是锁的同一个对象

  • 如果锁的是同一个对象,那么会产生互斥效果,一个线程没有执行完,另外一个线程阻塞等待.
  • 锁的不是同一个对象,那么就不会产生互斥效果,并行的执行
  • 如果没有加锁,那么也是会与其他线程并行的执行

然后具体情况具体分析,可能分为多种情况-->这种情况就要考虑任务调度器的调度执行了.--->分多种情况去考虑即可

参考 :

黑马程序员JUC视频-->哔哩哔哩

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

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

相关文章

从Zemax OpticStudio导入光学系统

摘要 ZemaxOpticStudio是一款广泛使用的光线追迹软件。VirtualLab Fusion可以从Zemax OpticStudio导入光学系统,包括完整3D位置信息和镜片玻璃。导入后,光学系统的结构数据将显示为单独的表面或可以组合成VirtualLab Fusion中的组件。VirtualLab Fusion可…

docker入门(一):在centOS虚拟机上安装docker

索引CentOS虚拟机安装1.下载CentOS镜像问题1-报错“您已输入用户名,客户机操作系统将保留此用户名”2.根据docker官方指导进行安装1.卸载旧版本(初次安装可以忽略)2.确保能联网后下载前置软件包3.设置镜像库(阿里版)4.…

CLIP后续--LSeg,GroupViT,ViLD

这个博客开了有两个月,一直没写成,最近封寝给它完成~躺平第三天 CLIP应用领域概览: 1. LSeg 原论文地址:https://arxiv.org/abs/2201.03546 代码:https://github.com/isl-org/lang-seg 这个图就很清楚的说明了zero…

mysql数据库管理

目录 一、MySQL数据库管理 1、库和表 2、常用的数据类型 3、char和varchar区别 二、查看数据库结构 三、SQL语句 1、SQL语句分类: 四、创建及删除数据库和表 五、管理表中的数据记录 六、修改表名和表结构 七、自增 八、填充 九、克隆表 十、清空表&am…

信号与系统1——Signals and Systems

信号与系统1——Signals and Systems一、Introduction1. Signals and Systems信号与系统(1) Signal信号(2) System系统2. Classification of Signals信号的分类(1) Continuous-time & discrete-time1) Continuous-Time signal连续时间信号2) Discrete-Time signal离散时间信…

【Hack The Box】linux练习-- Passage

HTB 学习笔记 【Hack The Box】linux练习-- Passage 🔥系列专栏:Hack The Box 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📆首发时间:🌴2022年9月7日🌴 &#x1f36…

浅析数据仓库和建模理论

第一章 认识数据仓库 1.1 数据仓库概念 数据仓库,英文名称为 Data Warehouse,可简写为 DW 或 DWH。数据仓库,是为企业所有级别的决策制定过程,提供所有类型数据支持的战略集合。它是单个数据存储,出于分析性报告和决…

BDD - SpecFlow SpecRun Web UI 多浏览器测试

BDD - SpecFlow & SpecRun 一个 Cases 匹配多个浏览器引言方案SpecFlow Runner profiles实现被测 Web Application创建一个 Class Libary 项目添加 NuGet PackagesSpecFlow & SpecRun 包添加 Selenium包其它包创建 Feature 文件配置 Default.srprofileDefault.srprofil…

MySQL的概念

MySQL的概念一.数据库的基本概念1、数据(Data)2、表3、数据库4、数据库管理系统(DBMS)4.1 关系数据库4.2 非关系型数据库 NoSQL5、数据库系统6、访问数据库的流程二.数据库系统发展史1.第一代数据库2.第二代数据库3.第三代数据库三…

JAVA多线程(MultiThread)的各种用法

多线程简单应用 单线程的问题在于,一个线程每次只能处理一个任务,如果这个任务比较耗时,那在这个任务未完成之前,其它操作就会无法响应。 如下示例中,点击了“进度1”后,程序界面就没反应了,强行…

类文件结构和初识一些字节码指令

文章目录类文件的结构为什么要了解字节码指令Class文件结构Java虚拟机规定的类结构魔数版本常量池访问标志类索引、父类索引、接口索引Ⅰ. interfaces_count(接口计数器)Ⅱ. interfaces[](接口索引集合)字段表集合**1. 字段表访问…

【React】使用 react-pdf 将数据渲染为pdf并提供下载

文章目录前言环境步骤1. 安装react脚手架2. 使用 create-react-app 创建项目 (首字母不要大写、不要使用特殊字符)3. 用 vscode 打开目录 react-staging4. yarn 启动项目5. 参考 react-pdf readme加入依赖6. 结合 github readme 和官方文档产出 demo 代码…

OpenGL 色彩替换

目录 一.OpenGL 色彩替换 1.IOS Object-C 版本1.Windows OpenGL ES 版本2.Windows OpenGL 版本 二.OpenGL 色彩替换 GLSL Shader三.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录 >> OpenGL ES 基础 零基础 OpenGL ES 学习路线推荐 : OpenGL ES 学习目录…

防抖debounce与节流throttle(63rd)

一、前言 当用户高频触发某一事件时,如窗口的resize、scroll,输入框内容校验等,此时这些事件调用函数的频率如果没有限制,可能会导致响应跟不上触发,出现页面卡顿,假死现象。此时,我们可以采用…

深度剖析NIKE Web3平台:为什么Web3对品牌很重要?

欢迎关注沉睡者IT,点上面关注我 ↑ ↑ 上周,NIKE 宣布了其新的 Web 3 平台 .SWOOSH,这是 NIKE Virtual Sudios (耐克虚拟工作室) 的一项新举措,将成为 NIKE 所有数字资产创作的“大本营”。继去年收购 RTFKT 之后,此次…

SpringBoot SpringBoot 原理篇 3 核心原理 3.4 启动流程【3】

SpringBoot 【黑马程序员SpringBoot2全套视频教程,springboot零基础到项目实战(spring boot2完整版)】 SpringBoot 原理篇 文章目录SpringBootSpringBoot 原理篇3 核心原理3.4 启动流程【3】3.4.1 看源码咯3 核心原理 3.4 启动流程【3】 …

负载均衡反向代理下的webshell上传

目录 架构如下: 实验环境: AntSword-Labshttps://github.com/AntSwordProject/AntSword-Labs 搭建环境: 启动环境: 测试连接: 地址不停的在漂移会造成的问题: 难点一:我们需要在每一台节点…

特征工程(六)—(2)利用LDA进行特征转换

1、LDA的手动处理 LDA(线性判别分析)是特征变换算法,也是有监督分类器。 和PCA一样,LDA的目标是提取一个新的坐标系,将原始的数据集投影到一个低维的空间中。 和PCA的主要区别是,LDA不会专注数据的方差&a…

[附源码]计算机毕业设计JAVA实验教学过程管理平台

[附源码]计算机毕业设计JAVA实验教学过程管理平台 项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM my…

【Hack The Box】linux练习-- Magic

HTB 学习笔记 【Hack The Box】linux练习-- Magic 🔥系列专栏:Hack The Box 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📆首发时间:🌴2022年11月21日🌴 &#x1f36…