java并发编程实战笔记-死锁

来源:互联网 发布:淘宝客服绩效考核方法 编辑:程序博客网 时间:2024/05/01 19:40

死锁的定义:

按书上所说,死锁就是自己拥有其他人需要的资源,同时又在等待其他人已经拥有的资源,并且每个人在获得所需要的资源之前都不会放弃自己已经有的资源。

死锁的类型:

1.简单的顺序死锁:
public class die1 {public Object lock1 = new Object();public Object lock2 = new Object();public void die1Mthod1(){synchronized(lock1){synchronized(lock2){}}}public void die1Mthod2(){synchronized(lock2){synchronized(lock1){}}}}
对于上线的类,如果只有一个线程串行执行的话,绝对不会发生死锁,但是如果超过两个线程,并且等待时间足够长,那么当一个线程在执行方法一同时另一个线程在执行方法2的时候就会出现死锁。因为两个线程持有对方需要的资源,程序会暂停执行,发生死锁。

2.动态的死锁:
public class die2 {public static Object fromAccount = new Object();public static Object toAccount = new Object();public static void transfer(Object fromAccout,Object toAccount,int money) throws InterruptedException{/*if(fromAccout.hashCode() < toAccount.hashCode()){Thread.sleep(3000);synchronized(fromAccout){synchronized(toAccount){System.out.println(Thread.currentThread().getName() + "交易金额+:" + money); }}}if(fromAccout.hashCode() > toAccount.hashCode()){Thread.sleep(3000);synchronized(toAccount){synchronized(fromAccout){System.out.println(Thread.currentThread().getName() + "交易金额! :" + money); }}}*//*未定义之前的锁顺序 *///Thread.sleep(3000);synchronized(fromAccout){Thread.sleep(1000);    (1)synchronized(toAccount){System.out.println("交易金额:" + money); }}}public static void main(String[] args){Thread thead1 = new Thread(new Runnable(){@Overridepublic void run() {try {die2.transfer(die2.fromAccount, die2.toAccount, 500);} catch (InterruptedException e) {e.printStackTrace();}}});Thread thead2 = new Thread(new Runnable(){@Overridepublic void run() {try {die2.transfer(die2.toAccount, die2.fromAccount, 100);} catch (InterruptedException e) {e.printStackTrace();}}});thead2.start();thead1.start();}}
上面所示,在一处是为了让线程一在获得了fromAccount这个锁后,延迟获得toAccount锁,让线程2获得,这样就能产生死锁,所以这样的代码虽然避免了死锁1的情况,但是会在程序运行的时候因为参数的原因导致了死锁。注释部分为解决方法。

3.协作对象的死锁:
public class die3 {static class die33{public static synchronized void method11() throws InterruptedException{//Thread.sleep(1000);method1();System.out.println("method11");}public static synchronized void method22(){System.out.println("method22");}}//注意:没有休眠,不会死锁,但是会引起栈的溢出public static synchronized void method1(){System.out.println("method1");}public static synchronized void method2() throws InterruptedException{//Thread.sleep(1000);die33.method22();System.out.println("method2");}public static void main(String[] args){Thread thead1 = new Thread(new Runnable(){@Overridepublic void run() {try {die3.method2();} catch (InterruptedException e) {e.printStackTrace();}}});Thread thead2 = new Thread(new Runnable(){@Overridepublic void run() {try {die3.die33.method11();} catch (InterruptedException e) {e.printStackTrace();}}});thead2.start();thead1.start();}}
因为虽然没有锁的顺序,但是在调用方法上,两个线程有可能会持有,两个不同的对象的锁,而有等待对方的锁,从而产生死锁。

解决死锁的办法:

1)接触顺序死锁的关系:如果die2的注释。
2)开放调用:在die3中,使用synchronized(this){}用于保护仅需要同步的操作,减少持有锁的时间。
3)使用定时锁,一定时间不能获得锁(tryLock),那么他将会放弃。

其他危险:

1)避免使用线程(api)的优先级,那会增加对平台的依赖,不正确的优先级,导致一些线程得不到cpu时间片,导致饥饿,所以使用java默认优先级。
2)线程重复执行相同的操作,而且总会失败,导致虽然没有阻塞进程,但是程序仍然没有执行,例如,两台机器同时发出消息,都发现了冲突,那么为失败,但是它们又会都等待相同的时间,从而导致程序一直失败的执行下去,所以可以让他们等待随机的时间,或者回退即可解决这样的活锁。
0 0