打字猴:1.700451419e+09
1700451419
1700451420 },“线程B”).start();
1700451421
1700451422 }
1700451423
1700451424 此段程序定义了两个资源A和B,然后在两个线程A、B中使用了该资源,由于两个资源之间有交互操作,并且都是同步方法,因此在线程A休眠1秒钟后,它会试图访问资源B的b2方法,但是线程B持有该类的锁,并同时在等待A线程释放其锁资源,所以此时就出现了两个线程在互相等待释放资源的情况,也就是死锁了,运行结果如下:
1700451425
1700451426 线程A进入A.a1()
1700451427
1700451428 线程B进入B.b1()
1700451429
1700451430 线程B试图访问A.a2()
1700451431
1700451432 线程A试图访问B.b2()
1700451433
1700451434 此种情况下,线程A和线程B会一直互等下去,直到有外界干扰为止,比如终止一个线程,或者某一线程自行放弃资源的争抢,否则这两个线程就始终处于死锁状态了。我们知道要达到线程死锁需要四个条件:
1700451435
1700451436 互斥条件:一个资源每次只能被一个线程使用。
1700451437
1700451438 资源独占条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
1700451439
1700451440 不剥夺条件:线程已获得的资源在未使用完之前,不能强行剥夺。
1700451441
1700451442 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
1700451443
1700451444 只有满足了这些条件才可能产生线程死锁,这也同时告诫我们如果要解决线程死锁问题,就必须从这四个条件入手,一般情况下可以按照以下两种方式来解决:
1700451445
1700451446 (1)避免或减少资源共享
1700451447
1700451448 一个资源被多个线程共享,若采用了同步机制,则产生的死锁可能性很大,特别是在项目比较庞大的情况下,很难杜绝死锁,对此最好的解决办法就是减少资源共享。
1700451449
1700451450 例如一个B/S结构的办公系统可以完全忽略资源共享,这是因为此类系统有三个特征:一是并发访问不会太高,二是读操作多于写操作,三是数据质量要求比较低,因此即使出现数据资源不同步的情况也不可能产生太大的影响,完全可以不使用同步技术。但是如果是一个支付清算系统就必须慎重考虑资源同步问题了,因为此类系统一是数据质量要求非常高(如果产生数据不同步的情况那可是重大生产事故),二是并发量大,不设置数据同步则会产生非常多的运算逻辑失效的情况,这会导致交易失败,产生大量的“脏”数据,系统可靠性将大大降低。
1700451451
1700451452 (2)使用自旋锁
1700451453
1700451454 回到前面的例子,线程A在等待线程B释放资源,而线程B又在等待线程A释放资源,僵持不下,那如果线程B设置了超时时间是不是就可以解决该死锁问题了呢?比如线程B在等待2秒后还是无法获得资源,则自行终结该任务,代码如下:
1700451455
1700451456 public void b2(){
1700451457
1700451458 try{
1700451459
1700451460 //立刻获得锁,或者2秒等待锁资源
1700451461
1700451462 if(lock.tryLock(2,TimeUnit.SECONDS)){
1700451463
1700451464 System.out.println(“进入B.b2()”);
1700451465
1700451466 }
1700451467
1700451468 }catch(InterruptedException e){
[ 上一页 ]  [ :1.700451419e+09 ]  [ 下一页 ]