जावा में म्यूटेक्स है?


110

क्या जावा में एक म्यूटेक्स ऑब्जेक्ट है या एक बनाने का तरीका है? मैं पूछ रहा हूं क्योंकि 1 परमिट के साथ शुरू की गई एक सेमाफोर ऑब्जेक्ट मुझे मदद नहीं करता है। इस मामले के बारे में सोचो:

try {
   semaphore.acquire();
   //do stuff
   semaphore.release();
} catch (Exception e) {
   semaphore.release();
}

यदि कोई अपवाद पहली अधिग्रहण में होता है, तो कैच ब्लॉक में रिलीज परमिट बढ़ाएगा, और सेमाफोर अब बाइनरी सेमाफोर नहीं है।

क्या सही तरीका होगा?

try {
   semaphore.acquire();
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}

क्या उपरोक्त कोड यह सुनिश्चित करेगा कि सेमाफोर द्विआधारी होगा?


Jav.util.concurrent.locks.AbstractQueuedSynchronizer के लिए javadoc देखें। इसका एक उदाहरण है कि कैसे एक म्यूटेक्स वर्ग लिखना है। -दबन्नर
जो

क्या आपको यह व्यवहार अनुभवजन्य रूप से पता चला? क्या कार्यान्वयन ऐसा है कि 1-परमिट सेमाफोर पर रिलीज () को निष्पादित करना एक अतिरिक्त परमिट जोड़ता है, भले ही यह वर्तमान में दूसरा हो, वास्तव में?
अशुभ

जवाबों:


112

इस पृष्ठ को देखें: http://www.oracle.com/technetwork/articles/javase/index-140767.html

इसका थोड़ा अलग पैटर्न है जो मुझे लगता है कि आप क्या देख रहे हैं:

try {
  mutex.acquire();
  try {
    // do something
  } finally {
    mutex.release();
  }
} catch(InterruptedException ie) {
  // ...
}

इस उपयोग में, आप केवल release()एक सफल के बाद कॉल कर रहे हैंacquire()


133

जावा में किसी भी ऑब्जेक्ट का उपयोग synchronizedब्लॉक के रूप में लॉक के रूप में किया जा सकता है । अपवाद होने पर यह लॉक को रिलीज़ करने का स्वचालित रूप से ध्यान रखेगा।

Object someObject = ...;

synchronized (someObject) {
  ...
}

आप इसके बारे में और अधिक यहाँ पढ़ सकते हैं: आंतरिक ताले और सिंक्रनाइज़ेशन


बहुत उपयोगी खरीदने के लिए मैं एक सेमाफोर का उपयोग करना चाहता था।
नोआम नेवो

11
@ नोअम: बस कोड की तुलना सेमाफोर से करें और उसके साथ synchronized, आप देखेंगे कि क्या बेहतर पठनीय और कम त्रुटि वाला है।
व्लाद

17
यदि आप किसी भिन्न विधि (जैसे transaction.begin(); transaction.commit()) में लॉक रिलीज़ करने की अपेक्षा करते हैं, तो सिंक्रनाइज़ किए गए कीवर्ड का उपयोग नहीं किया जा सकता है ।
होसम ऐली

और इसका ऑब्जेक्ट ओरिएंटेड नहीं है। यह निम्न स्तर के सिंक्रोनाइजेशन का बहुत हिस्सा है
अंशुलकत्ता

यह भी देखें someObject.wait(timeout)और someObject.notify()जब आप इस उत्तर के कोड को देख रहे हों।
डेनियल एफ

25
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


private final Lock _mutex = new ReentrantLock(true);

_mutex.lock();

// your protected code here

_mutex.unlock();

5
किस तरह से यह पहले से ही प्रदान किए गए समाधानों से बेहतर है? मूल प्रश्नकर्ता को होने वाली समस्या को कैसे हल करता है?
मार्टिन

@Martin: "Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements."से: docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… ... हालांकि आपके पास एक बिंदु है। आर्गव का उत्तर इन परिचालनों का वर्णन या व्याख्या नहीं करता है।
FrustratedWithFormsDesigner

3
यह एक पुनरावर्ती म्यूटेक्स है जो एक ही धागे से कई री-लॉक की अनुमति देगा, जो समस्याग्रस्त हो सकता है। एक "सच", मूल म्यूटेक्स (गैर-पुनरावर्ती, सी ++ - शैली) एक बार में केवल एक लॉक की अनुमति देगा। यदि आप अपनी लाइन को बदल देते हैं private final ReentrantLock _mutex = ..., तो आप थ्रेडहोल्ड की संख्या वापस करने के लिए getHoldCount () का उपयोग कर सकते हैं । (आप Conditionइसे रोकने के लिए आवेदन कर सकते हैं । एपीआई देखें ।)
एनटैंगल्डलूप्स

16

किसी ने भी स्पष्ट रूप से इसका उल्लेख नहीं किया है, लेकिन इस तरह का पैटर्न आमतौर पर सेमाफोर के लिए अनुकूल नहीं है। कारण यह है कि कोई भी धागा एक सेमाफोर जारी कर सकता है, लेकिन आप आमतौर पर केवल मालिक धागा चाहते हैं जो मूल रूप से अनलॉक करने में सक्षम हो । इस केस केस के लिए, जावा में, हम आमतौर पर रीएंन्ट्रान्लॉक्स का उपयोग करते हैं, जिसे इस तरह बनाया जा सकता है:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

private final Lock lock = new ReentrantLock(true);

और उपयोग का सामान्य डिज़ाइन पैटर्न है:

  lock.lock();
  try {
      // do something
  } catch (Exception e) {
      // handle the exception
  } finally {
      lock.unlock();
  }

यहाँ जावा स्रोत कोड में एक उदाहरण है जहाँ आप इस पैटर्न को क्रिया में देख सकते हैं।

रेन्ट्रेंट लॉक्स को निष्पक्षता का समर्थन करने का अतिरिक्त लाभ है।

यदि आपको गैर-स्वामित्व-रिलीज़ शब्दार्थ की आवश्यकता है, तो केवल सेमाफ़ोर्स का उपयोग करें।


5
वास्तव में यह इस प्रश्न के लिए (केवल) सही उत्तर होना चाहिए। सेमाफोर और आपसी बहिष्करण लॉक के बीच अंतर की स्पष्ट व्याख्या। एक सेमाफोर का उपयोग करना एक count=1पारस्परिक बहिष्करण ताला नहीं है।
काहुआ

3
खुशी है कि किसी ने इशारा किया। संसाधन के लिए विशेष पहुँच के लिए म्यूटेक्स जाने का रास्ता है। बाइनरी सेमाफोर म्यूटेक्स नहीं हैं, सिमाफोरस को सिग्नलिंग तंत्र के रूप में अधिक उपयोग किया जाना चाहिए।
शिवम त्रिपाठी

रूबल: तो है lockजैसे ReentrantLockएक mutex? मुझे यकीन नहीं है कि क्यों mutexऔर binary semaphoreसमान इकाई होने के लिए समान लिया जा रहा है। Semaphoreकिसी भी धागे से जारी किया जा सकता है, ताकि रखवाली की गारंटी न हो critical section। कोई विचार?
CuriousMind

@ कैहुआ: मैं आपके विचार से गूंजता हूं। यह उत्तर कुंजी अंतर लाता है
CuriousMind

6

मुझे लगता है कि आपको इसके साथ प्रयास करना चाहिए:

जबकि सेमाफोर आरंभीकरण:

Semaphore semaphore = new Semaphore(1, true);

और अपने में Runnable Implementation

try 
{
   semaphore.acquire(1);
   // do stuff

} 
catch (Exception e) 
{
// Logging
}
finally
{
   semaphore.release(1);
}

इस तरह से मैंने इसे किया है, लेकिन अगर यह जाने का रास्ता है तो मुझे पूरा यकीन नहीं है।
अलग कर

1
Docs.oracle.com/javase/7/docs/api/java/util/concurrent/… के अनुसार "कोई आवश्यकता नहीं है कि परमिट जारी करने वाले थ्रेड को अधिग्रहित करके उस परमिट को अधिग्रहित किया जाना चाहिए। एक सेमाफोर का सही उपयोग है। अनुप्रयोग में प्रोग्रामिंग सम्मेलन द्वारा स्थापित। " यदि अधिग्रहण एक अपवाद फेंकता है, तो अंत में रिलीज गलत तरीके से एक परमिट जारी करेगी। इस सूत्र में अन्य उदाहरण सही प्रवाह दिखाते हैं।
ब्रेंट के।

3

मूल पोस्ट में गलती अधिग्रहण लूप के अंदर () कॉल सेट है। यहाँ "बाइनरी" सेमाफोर (म्यूटेक्स) का उपयोग करने का एक सही तरीका दिया गया है:

semaphore.acquire();
try {
   //do stuff
} catch (Exception e) {
   //exception stuff
} finally {
   semaphore.release();
}

1

यह सुनिश्चित करने के लिए कि एक Semaphoreद्विआधारी है आपको केवल यह सुनिश्चित करने की आवश्यकता है कि आप अर्ध-निर्माण करते समय परमिट की संख्या 1 के रूप में पास करें। Javadocs में थोड़ा और अधिक स्पष्टीकरण की है।


1

प्रत्येक ऑब्जेक्ट का लॉक म्यूटेक्स / सेमाफोर डिज़ाइन से थोड़ा अलग है। उदाहरण के लिए पिछली नोड के लॉक को जारी करने और अगले एक पर कब्जा करने के साथ जुड़े नोड्स को सही ढंग से लागू करने का कोई तरीका नहीं है। लेकिन म्यूटेक्स के साथ इसे लागू करना आसान है:

Node p = getHead();
if (p == null || x == null) return false;
p.lock.acquire();  // Prime loop by acquiring first lock.
// If above acquire fails due to interrupt, the method will
//   throw InterruptedException now, so there is no need for
//   further cleanup.
for (;;) {
Node nextp = null;
boolean found;
try { 
 found = x.equals(p.item); 
 if (!found) { 
   nextp = p.next; 
   if (nextp != null) { 
     try {      // Acquire next lock 
                //   while still holding current 
       nextp.lock.acquire(); 
     } 
     catch (InterruptedException ie) { 
      throw ie;    // Note that finally clause will 
                   //   execute before the throw 
     } 
   } 
 } 
}finally {     // release old lock regardless of outcome 
   p.lock.release();
} 

वर्तमान में, इस तरह की कोई कक्षा नहीं है java.util.concurrent, लेकिन आप यहाँ म्यूटेक्स कार्यान्वयन पा सकते हैं । मानक पुस्तकालयों के लिए, सेमाफोर यह सब कार्यक्षमता प्रदान करता है और बहुत कुछ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.