线程的死锁和死锁解决的实际案例

面试线程还是大头,不能有一丝一毫的模糊。

先来看死锁:就是多个锁和多个线程之间发生的故事,这里以俩个锁和俩个线程为例子。

锁1、锁2、线程1、线程2

当线程1获取锁1之后,线程2也获取了锁2,这是线程1又开始获取锁2(嵌套获取),线程2又想获取锁1(嵌套1获取),这种情况下线程1会等着线程2释放锁2,线程2会等着线程1释放锁1,然后就会形成了死锁。

具体代码:

public class deadLock implements Runnable{

	//1.创建俩把锁
	public static final Object object1=new Object();
	public static final Object object2=new Object();
	boolean boo;
	@Override
	public void run() {
		if(boo) {
			synchronized (object1) {
				System.out.println("进入1锁");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (object2) {
					System.out.println("进入2锁");
				}
			}
		}else {
			synchronized(object2) {
				System.out.println("进入2锁");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (object1) {
					System.out.println("进入1锁");
				}
			}
		}
		
	}
	
	
}

测试代码:

public static void main(String[] args) {
		deadLock d1=new deadLock();
		deadLock d2=new deadLock();
		d1.boo=true;
		d2.boo=false;
		Thread t1=new Thread(d1);
		Thread t2=new Thread(d2);
		t1.start();
		t2.start();
	}

怎么解决呢?

这种解决方式可以有三种,

1.顺序取锁

2.设置锁释放时间(可以使用Lock来实现)

3.预防死锁

接下来贴出第一个方式的代码:

public class openLock implements Runnable{
	
	public static final Object object=new Object();
	public static final Object object1=new Object();
	boolean bool;
	@Override
	public void run() {
		if(bool) {
			synchronized (object) {
				System.out.println("进入1锁");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (object1) {
					System.out.println("进入二锁");
				}
			}
		}else {
			synchronized (object) {
				System.out.println("进入1锁");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized (object1) {
					System.out.println("进入2锁");
				}
			}
		}
		
	}
	
	
}

对比死锁的代码来看,其实就是让所有的线程获取所得顺序是一样的,这样子的话就不会存在什么线程死锁的情况出现。

第二种方法:

public class OpenLock implements Runnable{
//第二种解决死锁的方式是:给锁设置一个时间,如果超过这个时间的或就放弃获取这个锁。
	Lock l1=new ReentrantLock();//锁1
	Lock l2=new ReentrantLock(); //锁2
	boolean bool;
	@Override
	public void run() {
		if(bool) {
			try {
			l1.lock();
			System.out.println("加上锁1");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("现在我在等待进入锁二了");
			if(l2.tryLock(200, TimeUnit.MILLISECONDS)){//注意在判断这一步就已经加上锁了
                try {
                    System.out.println("进入锁二");
                }finally {
                    l2.unlock();
                }
            }else{
                System.out.println("锁二一直被占用,算了我不进去了");
            }
			
			} catch (InterruptedException e) {
				e.printStackTrace();
			}finally {
				l1.unlock();
			}
		}else {
			l2.lock();
			try {
				System.out.println("进入锁二");
				Thread.sleep(1000);
				System.out.println("现在我在等待进入锁1了");
				if(l1.tryLock(200,TimeUnit.MILLISECONDS)) {
					
					try {
						System.out.println("进入锁一");
					}finally {
						l1.unlock();
					}
				}else {
					System.out.println("等带时间太长了,我不等了。");
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}finally {
				
			}
		}
		
	}
	
}

这种方法就是利用Lock来实现的,Lock锁有一种说法叫做可中断锁,意思是当等待的线程达到一定的时间之后,就不会再去等待了,它会放弃运行这个锁方法,而去执行其他方法。

死锁和解决代码在这里,还是得每天都要写一遍的。孰能生巧多写才会理解的更深。

你可能感兴趣的:(线程,Java)