八锁问题带你理解对象锁和类锁

  • 8锁问题演示
    • 1.标准访问
    • 2.在邮件方法中暂停4秒,请问先打印邮件还是短信
    • 3.新增普通sayHello方法,请问先打印邮件还是hello
    • 4.两部手机,请问先打印邮件还是短信
    • 5.两个静态同步方法,同一部手机,请问先打印邮件还是短信
    • 6.两个静态同步方法,两部手机,请问先打印邮件还是短信
    • 7.1个静态同步方法,1个普通同步方法,同一部手机,请问先打印邮件还是短信
    • 8.1个静态同步方法,1个普通同步方法,两部手机,请问先打印邮件还是短信
  • 8锁理论解释

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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {phone.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {phone.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {//phone.sendSMS();phone.sayHello();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {//phone.sendSMS();//phone.sayHello();phone2.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {phone.sendSMS();//phone.sayHello();//phone2.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {//phone.sendSMS();//phone.sayHello();phone2.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {phone.sendSMS();//phone.sayHello();//phone2.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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 blocke.printStackTrace();}},"A").start();Thread.sleep(100);new Thread(()->{try {//phone.sendSMS();//phone.sayHello();phone2.sendSMS();} catch (Exception e) {// TODO Auto-generated catch blocke.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并发编程-八锁问题带你彻底理解对象锁和类锁相关推荐

  1. Java并发编程与技术内幕:线程池深入理解

    林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要: 本文主要讲了Java当中的线程池的使用方法.注意事项及其实现源码实现原理,并辅以实例加 ...

  2. java并发编程实战学习笔记之基础知识与对象的共享

    第二章:线程安全性 2.1 什么是线程安全性 可以被多个线程调用,并且在线程之间不会出现错误的交互 方法内的局部变量不需要保护,因为它存储在栈中,是每个线程独有的 2.2 原子性 一个共享变量可以定义 ...

  3. java并发编程第一课 线程的创建、停止和状态变更

    开篇词: 由点及面,搭建你的 Java 并发知识网 你好,欢迎学习<Java 并发编程核心 78 讲>,我是讲师星星,一线互联网公司资深研发工程师,参与过集团内多个重点项目的设计与开发. ...

  4. 简明高效的 Java 并发编程学习指南

    你好,我是宝令,<Java 并发编程实战>专栏作者,很高兴你能看到这篇内容. 对于一个Java程序员而言,能否熟练掌握并发编程是判断他优秀与否的重要标准之一.因为并发编程是Java语言中最 ...

  5. Java并发编程(06):Lock机制下API用法详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Lock体系结构 1.基础接口简介 Lock加锁相关结构中涉及两个使用广泛的基础API:ReentrantLock类和Condition接 ...

  6. Java并发编程(六):从CPU缓存一致性协议到JMM(Java内存模型)

    注:本系列主要注重并发编程这块儿,JVM内容很多,会另外开专栏总结,此系列可能只是会稍微提及 一.跨平台和JVM 经过前面几篇博文的介绍,我们知道,任何编程语言编写的程序要想被计算机执行,都必须被翻译 ...

  7. Java 并发编程解析 | 如何正确理解Java领域中的锁机制,我们一般需要掌握哪些理论知识?

    苍穹之边,浩瀚之挚,眰恦之美: 悟心悟性,善始善终,惟善惟道! -- 朝槿<朝槿兮年说> 写在开头 提起Java领域中的锁,是否有种"道不尽红尘奢恋,诉不完人间恩怨"的 ...

  8. Java 并发编程—有锁互斥机制及AQS理论

    原文作者:Java并发编程 原文地址:AQS这样学就很简单了 目录 一.有锁互斥机制 二.AQS如何实现互斥 三.结语 如果你是道格李,你要实现一套机制来保证线程互斥,你会如何实现呢?你肯定不会一上来 ...

  9. 学习笔记:Java 并发编程④_无锁

    若文章内容或图片失效,请留言反馈. 部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 视频链接:https://www.bilibili.com/video/av81461839 配套资料: ...

最新文章

  1. 将视频插入视频:CVPR2019论文解析
  2. [数据结构] 散列表(哈希表)
  3. Codeforces 671E Organizing a Race (贪心、线段树)
  4. boost::geometry::compress_variant用法的测试程序
  5. docker学习笔记(一)docker入门
  6. c++中类型用new和不用new的区别
  7. 带有Gradle的Spring Boot Web应用程序
  8. 支付宝新版SDK-PC扫码支付-手机浏览器H5支付
  9. python123电脑登录不了_python(14)- 简单练习:登录账户失败三次,账户自动锁定...
  10. 5.css企业开发经验,习惯盒模型,层模型
  11. 牛刀:中国未来房价基本走势…
  12. linux7设置广播,中标麒麟Linux7 如何关闭广播消息
  13. 让你秒读懂阿里云数据库架构与选型
  14. 常山浙西计算机学校,常山这所最早的学校你上过吗?历经三个世纪,他依然在最初的地方等你……...
  15. IOS界面push跳转后navigationController不显示
  16. iosetup mysql_InnoDB: Error: io_setup() failed with EAGAIN
  17. tf.matmul - 矩阵乘法
  18. 从传统金融变身科技公司后,2017年的平安交了这样一份答卷
  19. 【DNA计算】DNA编码----笔记1
  20. IMT-2020(5G)推进组最新工作进展

热门文章

  1. 深入浅出Shell编程: Shell 变量【ZT】
  2. 怎么讲d 盘里的软件弄到桌面_GNOME 2 粉丝喜欢 Mate Linux 桌面的什么?
  3. 随想:增强类的重用性
  4. android返回上一级代码,Android实践11 | 利用intent返回数据给上一级activity
  5. php2个栈写一个队列,【数据结构】栈面试题--两个栈实现一个队列
  6. cadence导入dxf文件_DXF如何导入为图纸?
  7. RK 3399 切换以太网卡
  8. 产品经理之深度学习促进产品(二)
  9. USB HID学习:数据包分析
  10. 一个使用多年的Makefile模板