2012-01-17 16 views
6

पर लॉक का इंतजार करने के लिए के साथ syncronized ब्लॉक को प्रतिस्थापित करना चाहता हूं।लॉक का उपयोग करते समय IllegalMonitorStateException से कैसे बचें Reentrantlock

private ReentrantLock lock = new ReentrantLock(); 

try 
{ 
    lock.lockInterruptably(); 
} 
catch(InterruptedException e) 
{ 
    Thread.currentThread.interrupt(); 
} 
finally 
{ 
    lock.unlock(); 
} 

समस्या यह है कि अंत में बिल्कुल भी होता है जब InterruptedException होता है: इस के लिए, मैं lockInterruptibly() विधि और मुहावरेदार ट्राई/अंत में ब्लॉक का उपयोग करें। इसका परिणाम IllegalMonitorStateException में होता है, क्योंकि लॉक वर्तमान धागे द्वारा नहीं होता है।

यह सरल कार्यक्रम इस साबित होता है:

public class LockTest 
{ 
public static void main(String[] args) 
{ 
    System.out.println("START"); 

    Thread interruptThread = new Thread(new MyRunnable(Thread.currentThread())); 
    interruptThread.start(); 
    ReentrantLock lock = new ReentrantLock(); 

    Thread takeLockThread = new Thread(new TakeLockRunnable(lock)); 
    takeLockThread.start(); 

    try 
    { 
     Thread.sleep(500); 
     System.out.println("Trying to take lock on thread " + Thread.currentThread().getName()); 
     lock.lockInterruptibly(); 
    } 
    catch (InterruptedException e) 
    { 
     e.printStackTrace(); 
    } 
    finally { 
     lock.unlock(); 
    } 

    System.out.println("DONE"); 
} 

private static class MyRunnable implements Runnable 
{ 
    private Thread m_thread; 

    private MyRunnable(Thread thread) 
    { 
     m_thread = thread; 
    } 

    @Override 
    public void run() 
    { 
     try 
     { 
      Thread.sleep(1000); 
     } 
     catch (InterruptedException e) 
     { 
      // ignore 
     } 
     System.out.println("Interrupting thread " + m_thread.getName()); 
     m_thread.interrupt(); 
    } 
} 

private static class TakeLockRunnable implements Runnable 
{ 
    private ReentrantLock m_lock; 

    public TakeLockRunnable(ReentrantLock lock) 
    { 
     m_lock = lock; 
    } 

    @Override 
    public void run() 
    { 
     try 
     { 
      System.out.println("Taking lock on thread " + Thread.currentThread().getName()); 
      m_lock.lock(); 
      Thread.sleep(20000); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
     finally { 
      m_lock.unlock(); 
     } 
    } 
} 
} 

यह प्रिंट इस उत्पादन:

 
START 
Taking lock on thread Thread-1 
Trying to take lock on thread main 
java.lang.InterruptedException 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:877) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1201) 
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:312) 
    at LockTest.main(LockTest.java:25) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
Exception in thread "main" java.lang.IllegalMonitorStateException 
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:127) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1239) 
    at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:431) 
    at LockTest.main(LockTest.java:32) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
Interrupting thread main 

क्या सबसे अच्छा तरीका है पर कोई विचार इस से बचने के लिए है?

उत्तर

18

lockInterruptibly() कॉल किया जाना चाहिए बाहर अंत में ब्लॉक। ध्यान दें, यह हमेशा Lock एपीआई (चाहे आप lock() या lockInterruptibly() का उपयोग करें) का उपयोग करने का प्रयास करें, क्योंकि "अनलॉक" काम नहीं करना चाहते हैं जब तक कि आपने लॉक प्राप्त नहीं किया हो।

try { 
    lock.lockInterruptibly(); 
    try { 
    // do locked work here 
    } finally { 
    lock.unlock(); 
    } 
} catch(InterruptedException e) { 
    Thread.currentThread.interrupt(); 
} 
+0

कोई भी डाउनवोट पर टिप्पणी करने की परवाह करता है? – jtahlborn

+0

मैं पहले 'isHeldByCurrentThread' का उपयोग कर रहा था, लेकिन सभी टिप्पणियों को पढ़ने के बाद, मुझे लगता है कि यह संस्करण केवल एकमात्र है जो वास्तव में सही है। –

+0

@WimDeblauwe आप किस टिप्पणी का जिक्र कर रहे हैं, और आप क्यों सोचते हैं कि 'isHeldByCurrentThread' सही नहीं है? –

2

बस एक बूलियन-ध्वज का उपयोग कर इस का ध्यान रखना चाहिए:

private ReentrantLock lock = new ReentrantLock(); 

boolean lockAcquired = false; 

try 
{ 
    lock.lockInterruptably(); 
    lockAcquired = true; 
} 
catch(InterruptedException e) 
{ 
    Thread.currentThread.interrupt(); 
} 
finally 
{ 
    if(lockAcquired) 
    { 
    lock.unlock(); 
    } 
} 
संबंधित मुद्दे