1.锁的八个问题
package juc.lock2;import java.util.concurrent.TimeUnit;/*** 锁的八个问题** @Author Rock Wang* @Time 2021/11/8*/class Phone {public synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception {System.out.println("------sendEmail");}public void getHello() {System.out.println("------getHello");}}public class Lock8{public static void main(String[] args) throws InterruptedException {Phone phone = new Phone();new Thread(()->{try {phone.sendSMS();} catch (Exception e) {e.printStackTrace();}},"AA").start();Thread.sleep(100);new Thread(()->{try {phone.sendEmail();} catch (Exception e) {e.printStackTrace();}},"AA").start();}}/*** @Description: 8锁* 1 标准访问,先打印短信还是邮件------sendSMS------sendEmail2 停4秒在短信方法内,先打印短信还是邮件------sendSMS------sendEmail3 新增普通的hello方法,是先打短信还是hello------getHello------sendSMS4 现在有两部手机,先打印短信还是邮件------sendEmail------sendSMS5 两个静态同步方法,1部手机,先打印短信还是邮件------sendSMS------sendEmail6 两个静态同步方法,2部手机,先打印短信还是邮件------sendSMS------sendEmail7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件------sendEmail------sendSMS8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件------sendEmail------sendSMS*/
synchronized实现同步的基础:Java中的每一个对象都可以作为锁。
具体表现为以下3种形式。
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的Class对象。
对于同步方法块,锁是Synchonized括号里配置的对象
2.公平锁和非公平锁
//公平锁:在上锁前询问是否有其他线程等待锁,效率低。
new ReentrantLock(true);
//非公平锁:其他线程可能抢不到锁,线程饿死,效率高。
new ReentrantLock();
3.可重入锁
synchronized(隐式,上锁解锁自动完成)
Lock(显式,手动加锁解锁)
什么是 “可重入”,可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。
使用 ReentrantLock的时候一定要手动释放锁,并且加锁次数和释放次数要一样。
4.死锁
所谓死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
必要条件
如果在一个系统中以下四个条件同时成立,那么就能引起死锁:
- 互斥:至少有一个资源必须处于非共享模式,即一次只有一个进程可使用。如果另一进程申请该资源,那么申请进程应等到该资源释放为止。
- 占有并等待:—个进程应占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有。
- 非抢占:资源不能被抢占,即资源只能被进程在完成任务后自愿释放。
- 循环等待:有一组等待进程 {P0,P1,…,Pn},P0 等待的资源为 P1 占有,P1 等待的资源为 P2 占有,……,Pn-1 等待的资源为 Pn 占有,Pn 等待的资源为 P0 占有。
我们强调所有四个条件必须同时成立才会出现死锁。循环等待条件意味着占有并等待条件,这样四个条件并不完全独立。
死锁处理方法
一般来说,处理死锁问题有三种方法:
- 通过协议来预防或避免死锁,确保系统不会进入死锁状态。
- 可以允许系统进入死锁状态,然后检测它,并加以恢复。
- 可以忽视这个问题,认为死锁不可能在系统内发生。
第三种解决方案为大多数操作系统所采用,包括 Linux 和 Windows。因此,应用程序开发人员需要自己编写程序,以便处理死锁。
死锁查找
第一步:jps -l (类似linux的 ps -ef)
查找进程号
第二步:jstack 进程号 (堆栈跟踪工具)
如果有死锁:Found 1 deadlock.
