1.锁的八个问题

  1. package juc.lock2;
  2. import java.util.concurrent.TimeUnit;
  3. /**
  4. * 锁的八个问题
  5. *
  6. * @Author Rock Wang
  7. * @Time 2021/11/8
  8. */
  9. class Phone {
  10. public synchronized void sendSMS() throws Exception {
  11. //停留4秒
  12. TimeUnit.SECONDS.sleep(4);
  13. System.out.println("------sendSMS");
  14. }
  15. public synchronized void sendEmail() throws Exception {
  16. System.out.println("------sendEmail");
  17. }
  18. public void getHello() {
  19. System.out.println("------getHello");
  20. }
  21. }
  22. public class Lock8{
  23. public static void main(String[] args) throws InterruptedException {
  24. Phone phone = new Phone();
  25. new Thread(()->{
  26. try {
  27. phone.sendSMS();
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. },"AA").start();
  32. Thread.sleep(100);
  33. new Thread(()->{
  34. try {
  35. phone.sendEmail();
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }
  39. },"AA").start();
  40. }
  41. }
  42. /**
  43. * @Description: 8锁
  44. * 1 标准访问,先打印短信还是邮件
  45. ------sendSMS
  46. ------sendEmail
  47. 2 停4秒在短信方法内,先打印短信还是邮件
  48. ------sendSMS
  49. ------sendEmail
  50. 3 新增普通的hello方法,是先打短信还是hello
  51. ------getHello
  52. ------sendSMS
  53. 4 现在有两部手机,先打印短信还是邮件
  54. ------sendEmail
  55. ------sendSMS
  56. 5 两个静态同步方法,1部手机,先打印短信还是邮件
  57. ------sendSMS
  58. ------sendEmail
  59. 6 两个静态同步方法,2部手机,先打印短信还是邮件
  60. ------sendSMS
  61. ------sendEmail
  62. 7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
  63. ------sendEmail
  64. ------sendSMS
  65. 8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
  66. ------sendEmail
  67. ------sendSMS
  68. */

synchronized实现同步的基础:Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象

2.公平锁和非公平锁

//公平锁:在上锁前询问是否有其他线程等待锁,效率低。
new ReentrantLock(true);
//非公平锁:其他线程可能抢不到锁,线程饿死,效率高。
new ReentrantLock();

3.可重入锁

synchronized(隐式,上锁解锁自动完成)
Lock(显式,手动加锁解锁)

什么是 “可重入”,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁

使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样。

4.死锁

所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

必要条件

如果在一个系统中以下四个条件同时成立,那么就能引起死锁:

  1. 互斥:至少有一个资源必须处于非共享模式,即一次只有一个进程可使用。如果另一进程申请该资源,那么申请进程应等到该资源释放为止。
  2. 占有并等待:—个进程应占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有。
  3. 非抢占:资源不能被抢占,即资源只能被进程在完成任务后自愿释放。
  4. 循环等待:有一组等待进程 {P0,P1,…,Pn},P0 等待的资源为 P1 占有,P1 等待的资源为 P2 占有,……,Pn-1 等待的资源为 Pn 占有,Pn 等待的资源为 P0 占有。

我们强调所有四个条件必须同时成立才会出现死锁。循环等待条件意味着占有并等待条件,这样四个条件并不完全独立。

死锁处理方法

一般来说,处理死锁问题有三种方法:

  1. 通过协议来预防或避免死锁,确保系统不会进入死锁状态。
  2. 可以允许系统进入死锁状态,然后检测它,并加以恢复。
  3. 可以忽视这个问题,认为死锁不可能在系统内发生。

第三种解决方案为大多数操作系统所采用,包括 Linux 和 Windows。因此,应用程序开发人员需要自己编写程序,以便处理死锁。

死锁查找

第一步:jps -l (类似linux的 ps -ef)
查找进程号

第二步:jstack 进程号 (堆栈跟踪工具)
如果有死锁:Found 1 deadlock.