Java多线程之8Lock问题解析


本文目录

1. 8Lock实例:
  1. 标准访问的时候,请问先打印邮件还是短信?
  2. sendEmail方法暂停4秒钟,请问先打印邮件还是短信?
  3. 新增Hello普通方法,请问先打印邮件还是Hello?
  4. 两部手机,请问先打印邮件还是短信?
  5. 两个静态同步方法,同1部手机 ,请问先打印邮件还是短信?
  6. 两个静态同步方法,有2部手机 ,请问先打印邮件还是短信?
  7. 1个静态同步方法,1个普通同步方法,有1部手机 ,请问先打印邮件还是短信?
  8. 1个静态同步方法,1个普通同步方法,有2部手机 ,请问先打印邮件还是短信?
2. 8Lock总结
3. 补充:当前类的Class对象和当前类的实例对象分别是什么?

8Lock实例:


1. 标准访问的时候,请问先打印邮件还是短信?


代码:

//资源类
class Phone{public  synchronized void sendEmail() {System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}
}
//主方法
public class Lock_8 {public static void main(String[] args) {Phone p=new Phone();new Thread(() ->{p.sendEmail();},"A").start();new Thread(() ->{p.getSMS();;},"B").start();}
}

结果:


解析:

  • 不知道,因为线程谁抢到了谁执行,一般情况下是A执行

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


代码:

//资源类
class Phone{public  synchronized void sendEmail() {Thread.sleep(4000);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{p.sendEmail();},"A").start();//强制让线程A先执行Thread.sleep(200);new Thread(() ->{p.getSMS();;},"B").start();}
}

结果:


解析:

  • 4秒后A先执行,紧接着B执行。
  • 因为休眠main线程之前A已经启动了,时间足够A运行,A会锁住资源类的入口(也就是对象)。所以A先执行。

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


代码:

//资源类
class Phone{public  synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(200);new Thread(() ->{p.sayHello();},"B").start();}
}

结果:


解析:

  • 先打印hello,虽然sendEmail锁住了资源类的入口(对象),因为sayHello未上锁,所以sayHello方法可以进入资源类。
  • 但是Thread.sleep()锁住了main线程,也就是hello打印出来的延迟时间就是休眠的设定时间。
加个普通方法后发现和同步锁无关

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


代码:

//资源类
class Phone{public  synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(2000);new Thread(() ->{p2.getSMS();},"B").start();}
}

结果:


解析:

  • 先打印SMS,因为锁的是资源类的入口,也就是对象,既然不是同一个对象,那肯定锁不住。并且线程B的执行和main线程的休眠时间相关。
换成两个对象后,不是同一把锁了,情况立刻变化。

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


代码:

//资源类
class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public static synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(5000);new Thread(() ->{p.getSMS();},"B").start();}
}

结果:


解析:

  • 先打印sendEmali,然后打印getSMS,因为静态同步锁,锁的是Phone.Class,所以B线程在A线程执行完之前进不去。
  • synchronized实现同步的基础:Java中的每一个对象都可以作为锁。

具体表现为以下3种形式。

1. 对于普通同步方法,锁是当前实例对象。
2. 对于静态同步方法,锁是当前类的Class对象。
3. 对于同步方法块,锁是Synchonized括号里配置的对象。

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


代码:

//资源类
class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public static synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(5000);new Thread(() ->{p2.getSMS();},"B").start();}
}

结果:


解析:

  • 看似和5不一样,其实是一回事,虽然两个对象,因为强制A先执行,所以A会锁住资源类,因此先打印sendEmail。

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


代码:

//资源类
class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(2);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p=new Phone();new Thread(() ->{try {p.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(1000);new Thread(() ->{p.getSMS();},"B").start();}
}

结果:


解析:

  • static方法锁锁的不是资源类,锁的是类对象,也就是说,不管new了几个,静态同步方法的类对象都是一个;而普通同步方法锁住的是new出来的对象。
  • 所有的静态同步方法用的也是同一把锁——类对象本身,
    这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。
    但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,
    而不管是否是同一个实例对象。

8. 1个静态同步方法,1个普通同步方法,有2部手机 ,请问先打印邮件还是短信?


代码:

//资源类
class Phone{public static synchronized void sendEmail() throws Exception {TimeUnit.SECONDS.sleep(4);System.out.println("sendEmail----------");}public synchronized void getSMS() {System.out.println("----------getSMS");}public void sayHello() {System.out.println("---hello---");}
}
//主方法
public class Lock_8 {public static void main(String[] args) throws Exception {Phone p1=new Phone();Phone p2=new Phone();new Thread(() ->{try {p1.sendEmail();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}},"A").start();//强制让线程A先执行Thread.sleep(1000);new Thread(() ->{p2.getSMS();},"B").start();}
}

结果:


解析:

  • P1锁住的不是资源类,而是类对象。线程1锁的是类对象,线程2锁的是实例对象,虽然看似是一个对象,然而两者不具备竞态条件,因此修改main休眠时间之后就会发现getSMS先执行。

8Lock总结

  1. 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻内,只能有唯一一个线程去访问这些synchronized方法
  2. 锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的synchronized方法
  3. 加个普通方法后发现和同步锁无关
  4. 换成两个对象后,不是同一把锁了,情况立刻变化。
  5. 都换成静态同步方法后,情况又变化
  6. 所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
  7. 所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!
  8. 一个静态同步方法 一个普通同步方法,一个非同步方法,那么三者是都不具备竞态条件的。

3. 补充:当前类的Class对象和当前类的实例对象分别是什么?

实例:

  • 简单理解,就是new,就是对类的实例化,创建这个类对应的实际对象,类只是对事物的描述,而实例化就相当于为这个描述新开辟了一块内存,可以改变这块区域里的各种属性(成员变量),当然,也可以实例化多块区域,只是不同的对象而已。

Class:

  • 注意这里C大写了,与类概念区分开,在java里,Class是一个实实在在的类,在包 java.lang 下,有这样一个Class.java文件,它跟我们自己定义的类一样,是一个实实在在的类,Class对象就是这个Class类的实例了。在Java里,所有的类的根源都是Object类,而Class也不例外,它是继承自Object的一个特殊的类,它内部可以记录类的成员、接口等信息,也就是在Java里,Class是一个用来表示类的类。(o(∩_∩)o 有点绕啊,抓住关键一点,Class是一个实实在在的类,可以为它创建实例,也就是本文后面提到的Class对象,也看叫做Class实例)。

java提供了下面几种获取到类的Class对象的方法:

1) 利用对象实例调用getClass()方法获取该对象的Class实例;
2) 使用Class类的静态方法forName(“包名+类名”),用类的名字获取一个Class实例
3) 运用 类名.class 的方式来获取Class实例;

我们知道java世界是运行在JVM之上的,我们编写的类代码,在经过编译器编译之后,会为每个类生成对应的.class文件,这个就是JVM可以加载执行的字节码。运行时期间,当我们需要实例化任何一个类时,JVM会首先尝试看看在内存中是否有这个类,如果有,那么会直接创建类实例;如果没有,那么就会根据类名去加载这个类,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便会为这个类产生一个Class对象(一个Class类的实例),用来表达这个类,该类的所有实例都共同拥有着这个Class对象,而且是唯一的。

Java多线程之8Lock问题解析相关推荐

  1. Java多线程之CAS深入解析

    Java多线程之CAS深入解析 目录: CAS是什么 CAS底层原理Unsafe深入解析 CAS缺点 引子:蚂蚁花呗一面:讲一讲AtomicInteger,为什么要用CAS而不是synchronize ...

  2. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  3. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

  4. Java多线程之Synchronized和Lock的区别

    Java多线程之Synchronized和Lock的区别 目录: 原始构成 使用方法 等待是否可以中断 加锁是否公平 锁绑定多个条件Condition 小结:Lock相比较Synchronized的优 ...

  5. Java多线程之CAS缺点

    Java多线程之CAS缺点 目录: 循环时间开销很大 只能保证一个共享变量的原子操作 引来ABA问题及解决方案(重点) 1. 循环时间开销很大 通过看源码,我们发现有个do while,如果CAS失败 ...

  6. Java多线程之volatile详解

    Java多线程之volatile详解 目录: 什么是volatile? JMM内存模型之可见性 volatile三大特性之一:保证可见性 volatile三大特性之二:不保证原子性 volatile三 ...

  7. Java多线程之Semaphore用法

    Java多线程之Semaphore用法 本文目录: Semaphore基本概念 Semaphore使用案例:3个停车位,6辆车去抢,走一辆,抢一个停车位. 1. Semaphore基本概念 在信号量上 ...

  8. Java多线程之CyclicBarrier用法

    Java多线程之CyclicBarrier用法 本文目录 CyclicBarrier的基本概念 CyclicBarrier的案例:集齐7颗龙珠就可以召唤神龙 1. CyclicBarrier的基本概念 ...

  9. Java多线程之CountDownLatch用法

    Java多线程之CountDownLatch用法 本文目录: CountDownLatch基本概念 CountDownLatch案例:6个同学陆续离开教室后班长才可以关门 CountDownLatch ...

最新文章

  1. [导入]日志 20071211(WCF,实验室产品)
  2. (进阶篇)Cookie与 Session使用详解
  3. Java中的 Switch 是如何支持 String 的?为什么不支持 long?
  4. Email 正则验证
  5. python if main_Python:if __name__ == '__main__'
  6. React 等框架使用 index 做 key 的问题
  7. access下如何配置两个vlan_不同vlan间的通信如何简单配置(三种方式) ?
  8. Discuz!NT 缓存设计简析
  9. win10运行YOLOv4+OPENCV+VS2017
  10. 迷茫中,要让人生更精彩
  11. JavaScript--数据结构算法之链表
  12. 在SharePoint 2010中使用jQuery
  13. evolving checkers players [Fogel and Chellapilla, 2002]
  14. 揭开银行U盾的秘密---签发CA证书:单向认证+双向认证(含java代码)
  15. 对overflow与zoom”清除浮动”的一些认识
  16. matlab单回路和串级控制回路,串级控制回路PID参数如何整定?
  17. 简单图形的输入输出练习
  18. JOI2014Final 飞天鼠
  19. SqlServer使用top 100 PERCENT 无法排序的问题
  20. 《写给大家看的设计书》(第四版)分享

热门文章

  1. USB设备被识别流程【转】
  2. 常用的 16 个 Sublime Text 快捷键
  3. Cool!15个创意的 CSS3 文本效果【下篇】
  4. Linux下配置安装PHP环境
  5. jvm类加载器以及双亲委派
  6. 可自动定时切换的选项卡/滑动门导航代码
  7. 2021牛客多校3 - Kuriyama Mirai and Exclusive Or(差分+倍增)
  8. CodeForces - 1455E Four Points(数学+几何)
  9. Aizu - 1407 Parentheses Editor(对顶栈+模拟)
  10. HDU - 3804 Query on a tree(树链剖分+线段树+离线处理)