一、什么是死锁?
死锁是指一组线程因为竞争资源而相互等待,导致永久阻塞的现象叫死锁
二、死锁发生的条件
- 互斥,共享资源 X 和 Y 只能被一个线程占用(锁的本身以互斥为前提)
- 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候,不释放共享资源 X(可破坏:一次性申请所有需要的资源)
- 不可抢占,其他线程不能强行抢占线程 T1 占有的资源(可破坏:没有竞争到资源的线程主动释放占有的资源)
- 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占 有的资源,就是循环等待(可破坏:改变执行的顺序)
三、破坏死锁条件
public class Account {
private String accountName;
private int balance;
public Account(String accountName, int balance) {
this.accountName = accountName;
this.balance = balance;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
public void debit(int amount){
this.balance-=amount;
}
public void credbit(int amount){
this.balance+=amount;
}
}
public class TransferAccount implements Runnable{
private Account fromAccount;
private Account toAccount;
private int amount;
public TransferAccount(Account fromAccount, Account toAccount, int amount) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
@Override
public void run() {
while (true) {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance() > amount) {
fromAccount.debit(amount);
toAccount.credbit(amount);
System.out.println(Thread.currentThread().getName() + "=======>" + fromAccount.getAccountName() + "=======>" + fromAccount.getBalance());
System.out.println(Thread.currentThread().getName() + "=======>" + toAccount.getAccountName() + "=======>" + toAccount.getBalance());
}
}
}
}
}
}
public class Allocator {
private List<Object> list = new ArrayList<>();
synchronized boolean apply(Object from,Object to){
if (list.contains(from) || list.contains(to)){
return false;
}
list.add(from);
list.add(to);
return true;
}
synchronized void free(){
list.clear();
}
}
public class TransferAccount02 implements Runnable {
private Account fromAccount;
private Account toAccount;
private int amount;
private Allocator allocator;
public TransferAccount02(Account fromAccount, Account toAccount, int amount, Allocator allocator) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
this.allocator = allocator;
}
@Override
public void run() {
while (true) {
if (allocator.apply(fromAccount, toAccount)) {
try {
if (fromAccount.getBalance() > amount) {
fromAccount.debit(amount);
toAccount.credbit(amount);
System.out.println(Thread.currentThread().getName() + "=======>" + fromAccount.getAccountName() + "=======>" + fromAccount.getBalance());
System.out.println(Thread.currentThread().getName() + "=======>" + toAccount.getAccountName() + "=======>" + toAccount.getBalance());
}
}finally {
allocator.free();
}
}
}
}
}
public class TransferAccount03 implements Runnable{
private Account fromAccount;
private Account toAccount;
private int amount;
static Lock fromLock = new ReentrantLock();
static Lock toLock = new ReentrantLock();
public TransferAccount03(Account fromAccount, Account toAccount, int amount) {
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.amount = amount;
}
@Override
public void run() {
while (true) {
if(fromLock.tryLock()){
if(toLock.tryLock()){
if (fromAccount.getBalance() > amount) {
fromAccount.debit(amount);
toAccount.credbit(amount);
System.out.println(Thread.currentThread().getName() + "=======>" + fromAccount.getAccountName() + "=======>" + fromAccount.getBalance());
System.out.println(Thread.currentThread().getName() + "=======>" + toAccount.getAccountName() + "=======>" + toAccount.getBalance());
}
}
}
}
}
}
public class AccountTest {
public static void main(String[] args) {
Account account01 = new Account("张三",20000);
Account account02= new Account("李四",20000);
ThreadPoolExecutor executorService = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);
Allocator allocator = new Allocator();
TransferAccount02 transferAccount01 = new TransferAccount02(account01,account02,20,allocator);
TransferAccount02 transferAccount02 = new TransferAccount02(account02,account01,10,allocator);
executorService.submit(transferAccount01);
executorService.submit(transferAccount02);
}
}