2012-12-06 48 views
9

避免Java多线程中死锁情况的策略之一是使用超时。 假设一个线程获得了一个资源的锁定,现在正在等待另一个资源的锁定。经过一段时间后,如果它无法获取resource2上的锁定,那么它应该停止等待resource2上的锁定。它也应该释放resource1上的锁。因此可以避免死锁。使用超时避免Java多线程中的死锁

但是如何在Java中实现它?如何显式“释放”锁?如何定义超时等待锁定。

什么是确切的java命令和语法。请问任何你好世界的例子?

+2

其他解决方案;总是以相同的顺序获得锁,或永远不会获得多个锁。 ;) –

+0

+1为'如何定义超时等待锁' – n611x007

回答

8

这里是2个锁和2个线程试图获取他们以不同的顺序一个人为的例子。没有超时,代码就会死锁。

public static void main(String[] args) throws Exception { 
    final ReentrantLock lock1 = new ReentrantLock(); 
    final ReentrantLock lock2 = new ReentrantLock(); 
    Runnable try1_2 = getRunnable(lock1, "lock 1", lock2, "lock 2"); 
    Runnable try2_1 = getRunnable(lock2, "lock 2", lock1, "lock 1"); 
    new Thread(try1_2).start(); 
    new Thread(try2_1).start(); 
} 

private static Runnable getRunnable(final ReentrantLock lock1, final String lock1Name, final ReentrantLock lock2, final String lock2Name) { 
    return new Runnable() { 
     @Override 
     public void run() { 
      try { 
       if (lock1.tryLock(1, TimeUnit.SECONDS)) { 
        System.out.println(lock1Name + " acquired in thread " + Thread.currentThread()); 
        if (lock2.tryLock(1, TimeUnit.SECONDS)) { 
         System.out.println(lock2Name + " acquired in thread " + Thread.currentThread()); 
         Thread.sleep(2000); 
        } else { 
         System.out.println("Could not acquire "+lock2Name + " in thread " + Thread.currentThread()); 
         lock1.unlock(); 
         System.out.println(lock1Name + " released in thread " + Thread.currentThread()); 
        } 
       } else { 
        System.out.println("Could not acquire " + lock1Name + " in thread " + Thread.currentThread()); 
       } 
      } catch (InterruptedException e) { 
       //you should not ignore it 
      } finally { 
       if (lock1.isHeldByCurrentThread()) lock1.unlock(); 
       if (lock2.isHeldByCurrentThread()) lock2.unlock(); 
      } 
     } 
    }; 
} 
+1

从Java并发实践中的例子! ;) –

+1

@assylias当调用对象的同步方法时,线程会自动尝试获取“锁定该对象”。而在使用“java.util.concurrent.locks.Lock”时,我们不会请求“锁定对象的对象”,我们正在调用其方法。所以我认为,要正确使用“锁定”类,我们不应将方法标记为同步。但是我们应该有一个与该对象关联的“Lock”实例。在调用代码之前(需要同步),我们应该在相关的锁上尝试tryLock()。 ---- Plz继续阅读下面的评论------ –

+0

@assylias 所以我们没有物理锁定我们调用的方法的对象,但逻辑上锁定。 就像我们在每个对象上都有一块黑板,在调用方法之前,我们只是在blackbord上写上“嘿,我已经锁定了!” 。我们实际上并没有锁定对象。 其他线程会检查黑板,看看有人说“他已锁定”。所以它不会继续。 对吗? –

3

Lock in Java

Use tryLock(timeout, timeunits); 

获取锁,如果它是在给定免费等待时间和 当前线程未被中断。如果锁可用,则此 方法立即返回立即,值为true

如果锁不 可用,那么当前线程用于线程 调度目的禁用并一直处于休眠状态的三种情况之一 情况:

的锁收购由当前线程;

或其他某个线程 中断当前线程,和锁获取的中断 支撑;

或指定的等待时间

3

可能这种帮助,

Lock lock = null; 
lock=....; 
if (lock.tryLock(15L, TimeUnit.SECONDS)) { 
    try { 
     ........ 
    } finally { 
     lock.unlock(); 
    } 
} else { 
     // do sumthing 
} 
0

Java 8+ Concurrency API你可以设置一个明确的时间为lock等待时,它的条件设定为:

private Lock lock = new ReentrantLock(); 
private Condition myCondition = lock.newCondition(); 

try{    
    myCondition.await(1200L, TimeUnit.MILLISECONDS); 
} catch (InterruptedException e) { 
    System.out.println((e); 
} finally{ 
    lock.unlock(); 
} 

锁定将等待,直到它收到一个signal()signalAll()从另一个线程或直到1.2秒的时间到期。