java线程研究---(10)Thread同步:死锁

死锁


synchronized块的乱用,会造成死锁。

下面来看看死锁形成的大致情况:

  • 线程T1,执行线程对象A
  • 线程T2,执行线程对象B
  • 线程对象A,里面有加锁的代码需要获得自己的锁,并且同时有另外一个加锁的代码需要获得线程对象B的锁。
  • 线程对象B,里面有加锁的代码需要获得自己的锁,并且同时有另外一个加锁的代码需要获得线程对象A的锁。
  • 简言之:
    • 线程对象A在获得自己的锁的时候,需要获得线程对象B的锁
    • 线程对象B在获得自己的锁的时候,需要获得线程对象A的锁
  • 那么这两个对象都在占用自己的锁的时候,想要获得对方对象的锁。
  • 因此,这两个对象都在等锁的池(lock pool)中,都处于等待拿锁的状态。
  • 所以死锁就形成了——两个对象会无限的等待下去。。。

来看看死锁示例代码:

DeadThreadA.java

package thread;

public class DeadThreadA implements Runnable {

	public DeadThreadB	deadThreadB;	// 想拿到对方线程对象的锁,就得先获得引用

	private int			i	= 0;
	private int			j	= 0;

	@Override
	public void run() {

		while (true) {
			synchronized (this) { // 首先占用自己对象的锁
				if (i >= 10)
					break;

				i++;
				for (int j = 0; j < 10000000l; j++)
					;
				System.out.println(Thread.currentThread().getName() + ": i=" + i);

				while (true) {
					synchronized (deadThreadB) {  // 在占用自己对象的锁的同时,需要获得deadThreadB的锁
						if (j >= 10) {
							break;
						}
						j++;
						for (int j = 0; j < 10000000l; j++)
							;
						System.out.println(Thread.currentThread().getName() + ": j=" + j);
					}
				}

			}

		}

	}

}

DeadThreadB.java

package thread;

public class DeadThreadB implements Runnable {

	public DeadThreadA	deadThreadA;	// 想拿到对方线程对象的锁,就得先获得引用
	private int			i	= 0;
	private int			j	= 0;

	@Override
	public void run() {

		while (true) {
			synchronized (this) { // 首先占用自己对象的锁
				if (i >= 10)
					break;

				i++;
				for (int j = 0; j < 10000000l; j++)
					;
				System.out.println(Thread.currentThread().getName() + ": i= " + i);

				while (true) {
					synchronized (deadThreadA) { // 在占用自己对象的锁的同时,需要获得deadThreadA的锁
						if (j >= 10) {
							break;
						}
						j++;
						for (int j = 0; j < 10000000l; j++)
							;
						System.out.println(Thread.currentThread().getName() + ": j= " + j);
					}
				}

			}

		}

	}

}

代码的几点说明:

  • synchronized()块,只支持传入对象,如果想拿对方线程对象的锁,那么首先得获得对方线程对象的引用。
  • 当前的两个 线程对象,首先是各自已经占用了自己的锁,同时再,都尝试去拿对方的锁。
  • 所以,先synchronized (this),在占用自己的锁的同时,(没有释放自己的锁)再去拿对方的锁:synchronized (deadThreadB), synchronized (deadThreadA)
  • 也就是说,当前线程,要同时拿两个锁:首先是拿到自己锁,然后再去尝试拿对方的锁。
执行类,如下

DeadThreadMain.java

package thread;

public class DeadThreadMain {

	public static void main(String ab[]) {
		DeadThreadA a = new DeadThreadA();
		DeadThreadB b = new DeadThreadB();

		b.deadThreadA = a; // 获得对方线程对象的引用
		a.deadThreadB = b; // 获得对方线程对象的引用

		Thread t1 = new Thread(a); 
		Thread t2 = new Thread(b);

		t1.start();
		t2.start();

	}
}


控制台就打印这么多,之后程序是一直运行的,但是就像死循环一样,永不停止了:
Thread-1: i= 1
Thread-0: i=1



根据示例代码,来具体讲一下死锁过程:
  • t1线程启动的时候,首先占用了a对象的锁
  • t2线程启动的时候,首先占用了b对象的锁
  • t1线程占用了a对象的锁的同时,尝试拿b对象的锁:b对象的锁,一直在t2线程手里
  • t2线程占用了b对象的锁的同时,尝试拿a对象的锁:a对象的锁,一直在t1线程手里
  • t1和t2线程都处于等待拿对方的锁的状态,
  • 死锁产生








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值