首页 Java Java基础 Java介绍八锁问题带你彻底理解对象锁和类锁

Java介绍八锁问题带你彻底理解对象锁和类锁

Feb 09, 2021 pm 06:06 PM
java

Java介绍八锁问题带你彻底理解对象锁和类锁

相关免费学习推荐:java基础教程

8锁问题演示

1.标准访问

/*手机类可以发邮件和发短信*/class Phone{
	public synchronized void sendEmail() throws Exception{
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				phone.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述
标准访问,先打印邮件还是短信.
不一定谁先被打印。取决于CPU的执行情况.激活他们的是main线程,后面谁先被调度,不知道。
为了保证效果,我们在A和B的代码之间加thread.sleep(100).此时,可以确保A先被打印。
解释:
只要一个资源类里面,不管它有多少个同步方法,只要一个线程先访问了资源类里面的任何一个同步方法,那么它锁的不是这一个方法,锁的是该方法所在的整个资源类。也就是说,锁的是对象。它锁的不是当前的方法。
也就是说,这些synchoronized的方法都属于同一个资源类里面,锁的是整个资源类。

2.在邮件方法中暂停4秒,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				phone.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

先打印邮件。同步方法获取的phone对象锁,sleep不会释放锁。到了时间会立即执行。所以先打印邮件方法
解释:
它与问题1类似。
只要一个资源类里面,不管它有多少个同步方法,只要一个线程先访问了资源类里面的任何一个同步方法,那么它锁的不是这一个方法,锁的是该方法所在的整个资源类。也就是说,锁的是对象。它锁的不是当前的方法。
举个例子:我和班长要用同一个手机打电话,我肯定要等班长打完电话才能接着打。班长用的过程中停网了一段时间,那我也只能等班长打完。

3.新增普通sayHello方法,请问先打印邮件还是hello

先打印hello

/*手机类可以发邮件和发短信*/class Phone{
	public synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				//phone.sendSMS();
				phone.sayHello();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述
解释:加个普通方法后发现和同步锁无关。因此它无需等待同步锁释放。
这里可以举一个例子。班长用它的手机要打电话。而我要向班长借手机充电线,这两个不互斥,因此可以在班长打电话完之前就借走充电线。

4.两部手机,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		Phone phone2=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				//phone.sendSMS();
				//phone.sayHello();
				phone2.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述

解释:这里可以举一个例子,班长用它的手机法邮件。我用我自己的手机打电话。那么谁先谁后就没有关系。

5.两个静态同步方法,同一部手机,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public static synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public static synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		Phone phone2=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				phone.sendSMS();
				//phone.sayHello();
				//phone2.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述
解释:可以与问题6一起分析

6.两个静态同步方法,两部手机,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public static synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public static synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		Phone phone2=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				//phone.sendSMS();
				//phone.sayHello();
				phone2.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述
解析:
static属于一个类。也就说,他不属于当前对象this的一个独立的个体。而是属于全局的class。这就要考虑对象锁和全局锁的区别。全局锁即类锁。此时不管是一个phone还是多个phone都来自于同一个类Phone类。现在不管你锁到了哪个对象,我都要等他释放完了这个锁才能使用。

7.1个静态同步方法,1个普通同步方法,同一部手机,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public static synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		Phone phone2=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				phone.sendSMS();
				//phone.sayHello();
				//phone2.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述
一个静态,一个普通。锁的是同一部手机。静态方法锁的是Class.相当于我们锁了一个校门,一个是普通同步方法,锁的是当前对象。比如教师普通的们。锁的对象不一样。就不冲突

8.1个静态同步方法,1个普通同步方法,两部手机,请问先打印邮件还是短信

/*手机类可以发邮件和发短信*/class Phone{
	public static synchronized void sendEmail() throws Exception{
		TimeUnit.SECONDS.sleep(4);		//表示暂停4秒,它是一个枚举类型
		System.out.println("***sendEmail");
	}
	public synchronized void sendSMS() throws Exception{
		System.out.println("***sendSMS");
	}
	public void sayHello(){
		System.out.println("***sayHello");
	}}public class Lock8Demo {
	public static void main(String[] args) throws InterruptedException {
		//创建一个资源类
		Phone phone=new Phone();
		Phone phone2=new Phone();
		new Thread(()->{
			try {
				phone.sendEmail();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"A").start();
		Thread.sleep(100);
		new Thread(()->{
			try {
				//phone.sendSMS();
				//phone.sayHello();
				phone2.sendSMS();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		},"B").start();
	}}
登录后复制

在这里插入图片描述

解释:这个跟上面是一样的。

8锁理论解释

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

加个普通方法后发现和同步锁无关。
换乘两个对象后,不是同一把锁了,情况立刻发生变化。
都换成静态同步方法后,情况立刻变化
所有的非静态同步方法用的都是同一把锁------实例对象本身

2.synchronized实现同步的基础:java中的每个对象都可以作为锁。
具体表现为以下3种形式:

  1. 对于普通同步方法,锁是当前实例对象
  2. 对于同步方法块,锁是synchronized括号里面配置的对象。
    比如在方法里写
    synchronized(this){
    }
  3. 对于静态同步方法,锁是当前类的Class对象。

当一个进程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常必须释放锁。
也就是说一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁。可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以无需等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。

所有的静态同步方法用的也是同一把锁-----类对象本身。
这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。(问题78)。即一个锁class,一个锁this,两者不冲突。
但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁。而不管是同一个实例对象的静态方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象。(问题56)

以上是Java介绍八锁问题带你彻底理解对象锁和类锁的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Java 中的完美数 Java 中的完美数 Aug 30, 2024 pm 04:28 PM

Java 完美数指南。这里我们讨论定义,如何在 Java 中检查完美数?,示例和代码实现。

Java 中的随机数生成器 Java 中的随机数生成器 Aug 30, 2024 pm 04:27 PM

Java 随机数生成器指南。在这里,我们通过示例讨论 Java 中的函数,并通过示例讨论两个不同的生成器。

Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

Java 版 Weka 指南。这里我们通过示例讨论简介、如何使用weka java、平台类型和优点。

Java 中的史密斯数 Java 中的史密斯数 Aug 30, 2024 pm 04:28 PM

Java 史密斯数指南。这里我们讨论定义,如何在Java中检查史密斯号?带有代码实现的示例。

Java Spring 面试题 Java Spring 面试题 Aug 30, 2024 pm 04:29 PM

在本文中,我们保留了最常被问到的 Java Spring 面试问题及其详细答案。这样你就可以顺利通过面试。

突破或从Java 8流返回? 突破或从Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

Java 中的时间戳至今 Java 中的时间戳至今 Aug 30, 2024 pm 04:28 PM

Java 中的时间戳到日期指南。这里我们还结合示例讨论了介绍以及如何在java中将时间戳转换为日期。

Java程序查找胶囊的体积 Java程序查找胶囊的体积 Feb 07, 2025 am 11:37 AM

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4

See all articles