首先说明一下,这篇博客需要:
1.需要有一定锁的基础知识,并且了解简单的锁机制,和死锁的产生原因。
2.需要一定的并发知识,及多线程知识。
3.以Java为载体
好吧,我们废话不多说,这就进入我们今天的主题。
熟悉并发编程的朋友应该对"死锁"(DeadLock)这个概念不会陌生,因为在我们的程序设计多个线程,多个锁,多个“竞态”资源的时候,如果处理不得当,就非常容易出现死锁。
问题1,死锁不能解决码?
熟悉JVM的朋友都知道,jdk1.2以前(绿色计划)我们的JVM采用的是用户态的线程,也就是我们Java的线程不需要操作系统的内核态线程的帮助,操作系统不会感知到用户态线程的存在。
但是在jdk1.2以后,JVM便不再采用用户态线程了,转而采用内核态线程(Kernel Thread),每一个处理器(CPU)对应多个内核态线程,每一个内核态线程对应多个轻量级进程,而我们Java中的线程就是映射到轻量级进程上的,所以,实际上就是将线程的创建,阻塞,调度等操作全部交由操作系统来完成。
不是说锁呢嘛?扯社么Java线程实现?
我们通过Java的线程实现可以发现其实底层是交给操作系统实现的,所以操作系统对死锁的处理与解决方式也就是Java对死锁的处理方式。
首先要声明一点。死锁问题是可以在操作系统层面被消灭的,比如,“银行家算法”,但是成本实在是太高了,所以我们目前的操作系统选择“鸵鸟策略”,遇到死锁不管,等着重启。
一旦死锁发生则采取专门的措施,解除死锁并以最小的代价恢复操作系统运行。死锁的解除(关键是代价最小):
1)重新启动2)撤消进程
3)剥夺资源
4)进程回退
所以我么得出结论,从实际触发,到目前为指,死锁问题是不可避免的。
我先把类的定义全部放在这里:
银行账户类Account:
/**
* 账户类
*/
public class Account {
//账户Id
private Long id;
//账户名称
private String name;
//账户余额
private long money;
//可重入锁
private Lock lock;
public Account() {
}
public Account(Long id, String name, long money) {
this.id = id;
this.name = name;
this.money = money;
this.lock = new ReentrantLock();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getMoney() {
return money;
}
public void setMoney(long money) {
this.money = money;
}
public Lock getLock() {
return lock;
}
}
转账接口类transferAccount:
/**
* 定义转账接口供银行使用
*/
public interface transferAccount {
void Dotransfer(Account from,Account to,int moeny);
}
场景一:死锁的出现
public class BackOfDp extends Thread{
private Account zs = new Account(123456L,"zs",2000L);
private Account ls = new Account(654321L,"ls",2000L);
@Test
public void fun1() {
//创建给张三给李四转账的线程
TransferLs t1 = new TransferLs();
//创建李四给张三转账的线程
TransferZs t2 = new TransferZs();
t1.start();
t2.start();
try{
t1.join();
t2.join();
}catch (InterruptedException e){
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("-------------------------------------------");
System.out.println(zs.getMoney());
System.out.println(ls.getMoney());
}
/**
* 锁定逻辑是先锁支出对象,再锁存入对像
*
*/
//张三给李四转账的线程
private class TransferLs extends Thread{
@Override
pub