Java多线程:线程8锁案例分析

2023-11-13

线程8锁案例分析

通过分析代码,推测打印结果,并运行代码进行验证

1、两个线程调用同一个对象的两个同步方法

  • 被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行。
public class Demo {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(() -> number.getOne()).start();

        new Thread(() -> number.getTwo()).start();
    }
}

class Number {
    public synchronized void getOne() {
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

one

two

2、新增Thread.sleep()给某个方法

  • 被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法的调用者是同一个,所以两个方法用的是同一个锁,先调用方法的先执行,第二个方法只有在第一个方法执行完释放锁之后才能执行。
public class Demo {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(() -> number.getOne()).start();

        new Thread(() -> number.getTwo()).start();
    }
}

class Number {

    public synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

//等待3秒

one

two

3、新增一个线程调用新增的一个普通方法

  • 新增的方法没有被synchronized修饰,不是同步方法,不受锁的影响,所以不需要等待。其他线程共用了一把锁,所以还需要等待。
public class Demo {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(() -> number.getOne()).start();

        new Thread(() -> number.getTwo()).start();

        new Thread(() -> number.getThree()).start();
    }
}

class Number {
    public synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }

    public void getThree() {
        System.out.println("three");
    }
}

输出结果如下:

three

//等待3秒

one

two

4、两个线程调用两个对象的同步方法,其中一个方法有Thread.sleep()

  • 被synchronized修饰的方法,锁的对象是方法的调用者。因为用了两个对象调用各自的方法,所以两个方法的调用者不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
public class Demo {
    public static void main(String[] args) {
        Number numberOne = new Number();
        Number numberTwo = new Number();

        new Thread(() -> numberOne.getOne()).start();

        new Thread(() -> numberTwo.getTwo()).start();
    }
}

class Number {
    public synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

two

//等待3秒

one

5、将有Thread.sleep()的方法设置为static方法,并且让两个线程用同一个对象调用两个方法

  • 被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。因为两个方法锁的对象不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
public class Demo {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(() -> number.getOne()).start();

        new Thread(() -> number.getTwo()).start();
    }
}

class Number {
    public static synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

two

//等待3秒

one

6、将两个方法均设置为static方法,并且让两个线程用同一个对象调用两个方法

  • 被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,所以两个方法用的是同一个锁,后调用的方法需要等待先调用的方法。
public class Demo {
    public static void main(String[] args) {
        Number number = new Number();

        new Thread(() -> number.getOne()).start();

        new Thread(() -> number.getTwo()).start();
    }
}

class Number {
    public static synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public static synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

//等待3秒

one

two

7、将两个方法中有Thread.sleep()的方法设置为static方法,另一个方法去掉static修饰,让两个线程用两个对象调用两个方法

  • 被synchronized和static修饰的方法,锁的对象是类的class对象。仅仅被synchronized修饰的方法,锁的对象是方法的调用者。即便是用同一个对象调用两个方法,锁的对象也不是同一个,所以两个方法用的不是同一个锁,后调用的方法不需要等待先调用的方法。
public class Demo {
    public static void main(String[] args) {
        Number numberOne = new Number();
        Number numberTwo = new Number();

        new Thread(() -> numberOne.getOne()).start();

        new Thread(() -> numberTwo.getTwo()).start();
    }
}

class Number {
    public static synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

two

//等待3秒

one

8、将两个方法均设置为static方法,并且让两个线程用同一个对象调用两个方法

  • 被synchronized和static修饰的方法,锁的对象是类的class对象。因为两个同步方法都被static修饰了,即便用了两个不同的对象调用方法,两个方法用的还是同一个锁,后调用的方法需要等待先调用的方法。
public class Demo {
    public static void main(String[] args) {
        Number numberOne = new Number();
        Number numberTwo = new Number();

        new Thread(() -> numberOne.getOne()).start();

        new Thread(() -> numberTwo.getTwo()).start();
    }
}

class Number {
    public static synchronized void getOne() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("one");
    }

    public static synchronized void getTwo() {
        System.out.println("two");
    }
}

输出结果如下:

//等待3秒

one

two

小结

  • 一个类里面如果有多个synchronized方法,在使用同一个对象调用的前提下,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其他的线程都只能等待,换句话说,某一时刻内,只能有唯一一个线程去访问这些synchronized方法。
  • 锁的是当前对象this,被锁定后,其他线程都不能进入到当前对象的其他的synchronized方法。
  • 加个普通方法后发现和同步锁无关。
  • 换成静态同步方法后,情况又变化。
  • 所有的非静态同步方法用的都是同一把锁:实例对象本身。
  • 也就是说如果一个对象的非静态同步方法获取锁后,该对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是其他对象的非静态同步方法因为跟该对象的非静态同步方法用的是不同的锁,所以毋须等待该对象的非静态同步方法释放锁就可以获取他们自己的锁。
  • 所有的静态同步方法用的也是同一把锁:类对象本身。
  • 这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间不会有竞争条件。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个对象的静态同步方法,还是其他对象的静态同步方法,只要它们属于同一个类的对象,那么就需要等待当前正在执行的静态同步方法释放锁。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程:线程8锁案例分析 的相关文章

随机推荐

  • MTK 调试记录

    MT8788 MT8183 使用CC1 CC2做OTG检测 CONFIG MTK USB TYPEC U3 MUX 关闭 打开一下宏 CONFIG TCPC CLASS y CONFIG TCPC MT6370 y CONFIG MTK U
  • 常见等价无穷小

    当 x 0 时 等 价 无 穷
  • c++stl和std_std :: replace()函数以及C ++ STL中的示例

    c stl和std C STL std replace 函数 C STL std replace function replace function is a library function of algorithm header it
  • IntelliJ IDEA的项目配置和创建项目(四)

    一 配置JDK 按 Ctrl Shift Alt S 快捷键就会弹出项目配置区 如下图 第一个红色区域是配置JDK的地方 第二个红色区域指的是项目编译后输出的路径 如果要设置Modules项目的jdk 那么可以在这一行设置 二 创建项目 创
  • MyBatis-Plus 官方文档

    myBatis plus 官方文档 https mp baomidou com
  • VUE父组件监听$emit事件,如何传递多个父组件自己的参数

    背景 子组件可以通过this emit change parm value1 parm2 value2 传递多个参数 父组件监听事件传参有两种方式 方式1 父组件自己无参数 方法名可以不用带参数 函数中的e代表change事件的对象 直接获
  • 数据库系统概论-数据库恢复技术

    1 事务的概念及其特性 恢复技术能保证事务的哪些特性 事务是用户定义的一个数据库操作序列 这些操作要么全做 要么全不做 是一个不可分割的工作单位 事务具有4个特性 原子性 Atomicity 一致性 Consistency 隔离性 Isol
  • Java6.0中Comparable接口与Comparator接口详解 下

    Part IV 说到现在 读者应该对Comparable接口有了大概的了解 但是为什么又要有一个Comparator接口呢 难道Java的开发者都吃饱撑着没事做吗 再谈Comparator接口之前 大家应该先了解一个叫 策略模式 的东东 一
  • WIN10操作系统 Visual Studio 2017 C# ASP.net Web 简单接口+MySQL数据库+NPOI导出到EXCEL开发、发布及部署到局域网详细教程(一)

    本文利用Visual Studio 2017 C 编写一个简单的WEB程序发布和部署到局域网内 目的是实现 在局域网内任意一台未安装OFFICE办公软件的电脑上打开浏览器后在地址栏输入IP地址和端口号 即可链接到WEB网页 点击 导出到EX
  • Linux 镜像文件ISO下载

    Linux 镜像文件ISO下载地址 http archive kernel org centos vault 7 5 1804 isos x86 64 选择 CentOS 7 x86 64 Minimal 1804 iso 下载就OK 下载
  • 华为机试题81-字符串字符匹配

    描述 判断短字符串S中的所有字符是否在长字符串T中全部出现 请注意本题有多组样例输入 数据范围 1 len S len T 200 进阶 时间复杂度 O n 空间复杂度 O n 输入描述 输入两个字符串 第一个为短字符串 第二个为长字符串
  • 登录工程二:现代 Web 应用的典型身份验证需求

    朋友就职于某大型互联网公司 前不久 在闲聊间我问他日常工作的内容 他说他所在部门只负责一件事 即用户与登录 而他的具体工作则是为各个业务子网站提供友好的登录部件 Widget 从而统一整个网站群的登录体验 同时也能令业务开发者不用花费额外的
  • 解决MySQL版本与JDBC驱动版本不对应导致的错误

    我的MySQL版本是5 7 21的 对应的JDBC驱动应该是mysql connector java 5 1 46 bin jar 如果使用低版本的驱动 就会出现如下错误 HTTP Status 500 javax servlet Serv
  • .exe已停止工作_R027---Uipath调用python程序的exe

    一 缘起 看到不少朋友问Uipath调用python的方法 这里说一个方法 调用python程序编译后的exe 其他开发语言的程序也可以这么调用 由于调用的是exe文件 所以 其实没有用到UiPath Python Activities 用
  • Ubuntu常用命令大全

    转自 https www jb51 net os Ubuntu 56362 html 一 文件 文件夹管理 ls 列出当前目录文件 不包括隐含文件 ls a 列出当前目录文件 包括隐含文件 ls l 列出当前目录下文件的详细信息 cd 回当
  • 层次分析法的理解

    AHP 层次分析法 层次分析法的特点 基本概念 重要性表 判断矩阵 为什么要引入判断矩阵呢 判断矩阵的特点 一致矩阵 为什么要定义一致矩阵呢 一致矩阵的特点 一致矩阵的引理 一致性检验的步骤 判断矩阵计算权重 算术平均法求权重 几何平均法
  • 一个很好用的小控件----给所有view右上角添加数字(类似未读消息之类的)

    下面这种效果 Badge 用法很简但 见下面的demo Created by Fangchao on 2015 2 25 EActivity R layout activity usercenter public class UserCen
  • 软件测试及原则

    软件测试 英语 software testing 描述一种用来促进鉴定软件的正确性 完整性 安全性和质量的过程 换句话说 软件测试是一种实际输出与预期输出间的审核或者比较过程 软件测试的经典定义是 在规定的条件下对程序进行操作 以发现程序错
  • 几种压缩算法

    一 行程长度压缩 原理是将一扫描行中的颜色值相同的相邻像素用一个计数值和那些像素的颜色值来代替 例如 aaabccccccddeee 则可用3a1b6c2d3e来代替 对于拥有大面积 相同颜色区域的图像 用RLE压缩方法非常有效 由RLE原
  • Java多线程:线程8锁案例分析

    线程8锁案例分析 通过分析代码 推测打印结果 并运行代码进行验证 1 两个线程调用同一个对象的两个同步方法 被synchronized修饰的方法 锁的对象是方法的调用者 因为两个方法的调用者是同一个 所以两个方法用的是同一个锁 先调用方法的