Java'da Mutex var mı?


111

Java'da bir Mutex nesnesi veya bir tane oluşturmanın bir yolu var mı? 1 izinle başlatılan bir Semafor nesnesi bana yardımcı olmadığı için soruyorum. Şu durumu düşünün:

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

ilk alımda bir istisna meydana gelirse, catch bloğundaki serbest bırakma izinleri artıracak ve semafor artık bir ikili semafor değildir.

Doğru yol olacak mı?

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

Yukarıdaki kod semaforun ikili olmasını sağlayacak mı?


Java.util.concurrent.locks.AbstractQueuedSynchronizer için javadoc'a bakın. Mutex sınıfının nasıl yazılacağına dair bir örnek var. -dbednar
joe

Bu davranışı deneysel olarak mı buldunuz? Uygulama, 1-izinli bir Semafor üzerinde release () 'i yürütmek, şu anda başka bir izin veriyor olsa bile, gerçekten de fazladan bir izin ekleyecek şekilde mi?
Whimusical

Yanıtlar:



134

Java'daki herhangi bir nesne bir synchronizedblok kullanılarak kilit olarak kullanılabilir . Bu ayrıca, bir istisna meydana geldiğinde otomatik olarak kilidin serbest bırakılmasını sağlayacaktır.

Object someObject = ...;

synchronized (someObject) {
  ...
}

Bununla ilgili daha fazla bilgiyi buradan okuyabilirsiniz: İçsel Kilitler ve Senkronizasyon


Çok faydalı bir satın alma semafor kullanmak istedim.
Noam Nevo

11
@Noam: kodu semaforla karşılaştırın ve ile synchronized, neyin daha iyi okunabilir ve daha az hataya açık olduğunu göreceksiniz.
Vlad

17
Kilidi farklı bir yöntemle (örneğin transaction.begin(); transaction.commit()) serbest bırakmayı bekliyorsanız, senkronize edilmiş anahtar sözcük kullanılamaz .
Hosam Aly

ve nesne yönelimli değil ... düşük seviyeli senkronizasyonun
çoğu

Ayrıca içine bakmak someObject.wait(timeout)ve someObject.notify()bu cevabın koduna bakarken.
Daniel F

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
Bu, halihazırda sağlanan çözümlerden ne şekilde üstün? Asıl soruyu soranın yaşadığı sorunu nasıl çözer?
Martin

@Martin:, "Lock implementations provide more extensive locking operations than can be obtained using synchronized methods and statements."from: docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/… ... bir noktaya sahip olmanıza rağmen. Argv'ın cevabı bu işlemleri göstermiyor veya açıklamıyor.
FrustratedWithFormsDesigner

3
Bu, sorunlu olabilen, aynı iş parçacığından birden çok yeniden kilitlemeye izin veren özyinelemeli bir mutekstir. "Doğru", temel bir muteks (özyinelemeli olmayan, C ++ stili) bir seferde yalnızca bir kilide izin verir. Çizginizi olarak değiştirirseniz , iş parçacığı yeniden kilitlemelerin sayısını döndürmek için getHoldCount ()private final ReentrantLock _mutex = ... kullanabilirsiniz . (Bunu önlemek için bir uygulayabilirsiniz . API'ye bakın .)Condition
EntangledLoops

16

Kimse bundan açıkça bahsetmedi, ancak bu tür bir kalıp genellikle semaforlar için uygun değildir. Bunun nedeni ise herhangi bir iş parçacığı bir semafor serbest, ancak genellikle sadece istediğiniz sahibi iplik başlangıçta kilidini muktedir kilitli . Bu kullanım durumu için Java'da genellikle şu şekilde oluşturulabilen ReentrantLocks kullanırız:

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

private final Lock lock = new ReentrantLock(true);

Ve olağan kullanım tasarım modeli şöyledir:

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

İşte java kaynak kodunda bu kalıbı çalışırken görebileceğiniz bir örnek.

Yeniden girişli kilitlerin adaleti destekleme ek faydası vardır.

Semaforları yalnızca sahiplik bırakmayan semantiğe ihtiyacınız varsa kullanın.


5
Aslında bu soru için (tek) doğru cevap bu olmalıdır. Semafor ve karşılıklı dışlama kilidi arasındaki farkların net açıklaması. Bir semafor kullanmak count=1, karşılıklı bir dışlama kilidi değildir.
Kaihua

3
Birinin işaret etmesine sevindim. Bir kaynak muteksine özel erişim için gidilecek yoldur. İkili semaforlar muteks değildir, semaforlar daha çok sinyal mekanizması olarak kullanılmalıdır.
Shivam Tripathi

Ruble: Öyleyse lockörneğin ReentrantLocka mutex? Neden mutexve binary semaphoreaynı varlık olarak kabul edildiğinden emin değilim . Semaphoreherhangi bir diş ile serbest bırakılabilir, bu nedenle korumayı garanti etmeyebilir critical section. Düşüncesi olan var mı?
CuriousMind

@Kaihua: Düşüncelerinizle rezonansa giriyorum. Bu cevap temel farkı getiriyor
CuriousMind

6

Bence şunu denemelisin:

Semafor başlatılırken:

Semaphore semaphore = new Semaphore(1, true);

Ve senin içinde Runnable Implementation

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

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

Ben de böyle yaptım, ancak bunun doğru olup olmadığından emin değilim.
Müstakil

1
Docs.oracle.com/javase/7/docs/api/java/util/concurrent/… 'e göre "Bir izni serbest bırakan bir iş parçacığının, edinme çağrısı yaparak bu izni alması gerekmemektedir . Semaforun doğru kullanımı uygulamada programlama kuralı ile kurulmuştur. " Edinme bir istisna atarsa, nihayetinde serbest bırakma yanlış bir şekilde bir izni serbest bırakır. Bu konudaki diğer örnekler doğru akışı gösterir.
Brent K.

3

Orijinal gönderideki hata, try döngüsü içinde Acire () çağrı kümesidir. "İkili" semafor (Mutex) kullanmak için doğru bir yaklaşım:

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

1

SemaphoreA'nın ikili olduğundan emin olmak için, semaforu oluştururken izin sayısını 1 olarak aktardığınızdan emin olmanız yeterlidir. Javadocs biraz daha açıklama var.


1

Her nesnenin kilidi Mutex / Semafor tasarımından biraz farklıdır. Örneğin, önceki düğümün kilidini serbest bırakıp bir sonrakini yakalayarak çapraz bağlantılı düğümleri doğru şekilde uygulamanın hiçbir yolu yoktur. Ancak mutex ile uygulanması kolaydır:

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();
} 

Şu anda içinde böyle bir sınıf yok java.util.concurrent, ancak Mutext uygulamasını burada Mutex.java'da bulabilirsiniz . Standart kütüphanelere gelince, Semaphore tüm bu işlevselliği ve çok daha fazlasını sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.