从头认识java-17.4 详解同步(5)- 死锁

这一章节我们来简单讨论一下死锁,其实死锁是一个比较大的话题,但是我这里只是根据我前面的银行转账的例子来说明,在后面会有详细的专栏来说明并发编程的各个方面的问题。

1.什么是死锁?

是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。


2.怎样会引起死锁?

(1) 互斥条件:一个资源每次只能被一个进程使用;

(2) 请求与保持条件:既拿着现有资源,又去申请其他资源,但申请不上一直被阻塞;

(3) 不剥夺条件:不能够通过优先级来剥夺资源使用权的资源;

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。


3.我们前面的例子是怎样引起死锁的?

(1)死锁产生的过程:

账号1原有200元
账号2原有300元
线程1:从账户1转300元到账户2 
线程2:从账户2转400元到账户1 


(2)引起死锁的代码块:

public void transfer(int fromAccount, int toAccount, double money) {
		if (accounts[fromAccount] < money) {
			System.out.println(Thread.currentThread().getName() + "出现死锁");
			return;
		}
		accounts[fromAccount] -= money;
		System.out.printf("从" + fromAccount + "账户转出%10.2f元,", money);
		accounts[toAccount] += money;
		System.out.printf("从" + toAccount + "账户转入%10.2f元,", money);
		System.out.printf("总数:%10.2f元", getTotal());
		System.out.println();
	}

(3)原因:

当转账的钱大于现有的余额,将会产生死锁


(4)解决方案:

但是由于现实业务不允许这种情况出现,因此我们直接return就解决了死锁的问题。


(5)如果是其他多线程竞争资源,里面不是像上面一样的return,而且等待,就会出现死锁的情况。


4.完整例子:

package com.ray.ch17;

public class Bank {
	private final double[] accounts;

	public double[] getAccounts() {
		return accounts;
	}

	public Bank(int n, double initBalance) {
		accounts = new double[n];
		for (int i = 0; i < accounts.length; i++) {
			accounts[i] = initBalance;
		}
	}

	public double getTotal() {
		double total = 0;
		for (int i = 0; i < accounts.length; i++) {
			total += accounts[i];
		}
		return total;
	}

	public void transfer(int fromAccount, int toAccount, double money) {
		if (accounts[fromAccount] < money) {
			System.out.println(Thread.currentThread().getName() + "出现死锁");
			// Thread.currentThread().wait();//如果是其他的多线程,可能在这里是wait,从而出现真正的死锁
			return;
		}
		accounts[fromAccount] -= money;
		System.out.printf("从" + fromAccount + "账户转出%10.2f元,", money);
		accounts[toAccount] += money;
		System.out.printf("从" + toAccount + "账户转入%10.2f元,", money);
		System.out.printf("总数:%10.2f元", getTotal());
		System.out.println();
	}

	public int size() {
		return accounts.length;
	}
}

package com.ray.ch17;

import java.util.Random;

public class TransferThread implements Runnable {

	private Bank bank;

	private final double MAX;

	public TransferThread(Bank bank, double max) {
		this.bank = bank;
		this.MAX = max;
	}

	@Override
	public void run() {
		while (true) {
			double amount = MAX * Math.random();
			int countOfAccount = bank.getAccounts().length;
			bank.transfer(new Random().nextInt(countOfAccount),
					new Random().nextInt(countOfAccount), amount);
		}
	}

}

package com.ray.ch17;

public class Test {

	public static void main(String[] args) {
		Bank bank = new Bank(100, 10000);
		for (int i = 0; i < 2; i++) {
			TransferThread transferThread = new TransferThread(bank, 10000);
			Thread thread = new Thread(transferThread);
			thread.start();
		}
	}
}


总结:这一章节简单介绍了死锁。


这一章节就到这里,谢谢。

-----------------------------------

目录



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值