难度
初级
学习时间
30分钟
适合人群
零基础
开发语言
Java
开发环境
- JDK v11
- IntelliJ IDEA v2018.3
友情提示
- 本教学属于系列教学,内容具有连贯性,本章使用到的内容之前教学中都有详细讲解。
- 本章内容针对零基础或基础较差的同学比较友好,可能对于有基础的同学来说很简单,希望大家可以根据自己的实际情况选择继续看完或等待看下一篇文章。谢谢大家的谅解!
1.温故知新
在 一章中介绍了 synchronized关键字 。
在 一章中介绍了 同步代码块/方法中的同步锁 。
在 一章中介绍了 同步代码块中的双重判断 。
在 一章中介绍了 死锁 。
现在我们来讲解 同步方法产生死锁的例子 。
2.同步方法中的锁
通过 一章的学习,我们知道了同步方法中只有两种锁:this锁和类对象类锁(类名.class)。
this锁:
非静态方法使用的是this锁。
类对象(类名.class)锁:
静态方法使用的是类对象锁(类名.class)。
3.同步方法死锁程序
通过 一章的学习,我们知道死锁需要两个或两个以上的线程:
再者就是让这两个线程各持有一把锁,再让线程thread1去要线程thread2的锁,线程thread2去要线程thread1的锁,这样死锁就形成了。
不管怎样,我们需要一个类和一个同步方法,来一个DeadLock类:
这里就有一个问题。
什么问题?
我们DeadLock里面只有一把同步锁,但我们有两个线程,如果要让两个线程各持有一个同步锁,那还差一把同步锁,怎么办?
这个好解决,我们创建两个对象这样就有两把锁:
有的小伙伴可能有点懵:为什么创建两个DeadLock对象就有两把同步锁了呢?
我们先一步一步来解释,首先,非静态方法同步方法是不是this锁?也就是调用当前同步方法的实例对象。
例如,这里创建的deadLock1对象:
当deadLock1对象去调用这个sayHi()方法时:
这里的this锁就是deadLock1对象。
同理,我们创建的deadLock2对象:
当deadLock2对象去调用它的sayHi()方法时:
这里的this锁就是deadLock2对象。
也就是说谁去调用sayHi()方法谁就是this锁的真身。
所以,我们创建两个DeadLock对象也就创建了两把同步锁。
好了,锁有了,线程也有了,但是它们没有关联起来,我们该使用哪种方式关联呢?
暂时我们使用匿名内部类方式好了:
在线程thread1里面使用deadLock1对象去调用sayHi()方法:
同样的,在线程thread2里面使用deadLock2对象去调用sayHi()方法:
我们可以看到sayHi()方法里面输出语句都是一样的:
这样没法区分谁是谁调用的,为了加以区分不同对象调用的信息,我们在DeadLock类中再来一个name属性,用作记录对象名称:
这样还不够,我们还要在DeadLock对象初始化的时候必须指定名称:
再在sayHi()方法中输出name属性值:
于是,我们的Main类中的代码也需要修改:
接着,我们写上启动线程的代码:
好了,写了这么多,将上面程序代码整理之后,再运行程序看看。
演示:
请写一个由同步方法产生的死锁程序。
请观察程序代码及结果。
代码:
DeadLock类:
Main类:
结果:
从运行结果来看,并没有发生死锁。
为什么没有发生死锁呢?
因为我们还缺少最关键的一步,那就是让两个线程相互竞争同步锁,所以死锁没有产生。
怎么让两个线程去竞争对方的锁呢?
只要 让一个线程里面的对象去调用另一个对象的同步方法 即可。
例如,我们的线程thread1:
它持有的同步锁是deadLock1:
现在只需在deadLock1对象里面去调用deadLock2对象的同步方法即可。怎么做呢?
我们只需将deadLock2对象传给deadLock1对象就可以了,通过给sayHi()方法添加一个类型为DeadLock类型的参数即可:
于是,我们的Main类也需要修改:
现在是deadLock1对象调用sayHi(DeadLock deadLock)方法时就持有deadLock2对象;
同理,deadLock2对象调用sayHi(DeadLock deadLock)方法时就持有deadLock1对象;
两个线程各自持有一把锁,还差的就是相互索要同步锁(即在deadLock1对象的sayHi(DeadLock deadLock)方法里面调用deadLock2对象的同步方法),修改DeadLock类:
请问大家:这样写可以吗?
这样是非常错误的,因为这就成了自己调用自己,即递归,但这还是一个死递归,毫无意义,所以不可以这样写。
综上所述,我们还得再添加一个同步方法,修改DeadLock类:
接着,我们需要修改sayHi()方法里面去调用形参deadLock的sayHello()方法:
好了,整个程序修改完毕,整理之后再运行程序看看。
演示:
请写一个由同步方法产生的死锁程序。
请观察程序代码及结果。
代码:
DeadLock类:
Main类:
结果:
从运行结果来看,我们成功了。
同步方法产生死锁的程序写完了,最后希望大家可以在面试的时候可以顺利通过此类题目,同时也希望大家在以后的开发中可以避免死锁。
总结
- 准备一个类。
- 类中准备两个同步方法,需要两个同步方法的原因是避免递归调用。
- 这两个同步方法都需要有一个类型为本类类型的参数。
- 在一个同步方法里面去调用传递进来的本类实例对象的同步方法。
- 创建两个本类实例对象。
- 创建两个线程,并与两个实例对象关联。
- 两个实例对象都调用各自的同步方法并将对方传递进去。
- 最后启动线程即可。
至此,Java中同步方法产生死锁的例子相关内容讲解先告一段落,更多内容请持续关注。
答疑
如果大家有问题或想了解更多前沿技术,请在下方留言或评论,我会为大家解答。
上一章
下一章
“全栈2019”Java多线程第二十一章:同步代码块产生死锁的例子
学习小组
加入同步学习小组,共同交流与进步。
- 方式一:关注头条号Gorhaf,私信“Java学习小组”。
- 方式二:关注公众号Gorhaf,回复“Java学习小组”。
全栈工程师学习计划
关注我们,加入“全栈工程师学习计划”。
版权声明
原创不易,未经允许不得转载!