Java Semaphore ve Mutex nedir – Java Concurrency MultiThread Örnek ile açıklanmıştır
Yayınlanan: 2015-03-12Java Eşzamanlılığı çok geniş bir konudur. Kullanmak için yüzlerce öğretici ve örnek mevcuttur. Bir süre önce Java'da Aynı Anda Birden Çok İş Parçacığı Çalıştırma ve farklı Senkronize Blok türleri hakkında birkaç ders yazdım.
Bu eğitimde şunları ele alacağız:
- Mutex'in Açıklaması
- Semaforun Açıklaması
- Ayrıntılarla İki Örnek
Başlayalım
Aşağıdaki açıklamayı okurken Let's keep this in mind
:
- Alışverişçi ve Müşteri örneğini alın
- Alışveriş yapan kişi dizüstü bilgisayar ödünç alıyor
- Müşteri gelip Dizüstü Bilgisayarı kullanabilir - müşterinin Dizüstü Bilgisayar kullanmak için bir anahtara ihtiyacı vardır
- Kullanımdan sonra - müşteri Dizüstü Bilgisayarı Shopper'a iade edebilir
Mutex nedir (Sadece 1 iş parçacığı):
Shopper'da bir Dizüstü Bilgisayarın anahtarı var. Bir müşteri, o anda anahtarı alabilir - bir Dizüstü Bilgisayar ödünç alabilir. Görev bittiğinde, Alışverişçi anahtarı sıradaki bir sonraki müşteriye verir (serbest bırakır).
Official Definition
:
“Mutex, tipik olarak, cannot be executed concurrently
re-entrant code
bir bölümüne erişimi seri hale getirmek için kullanılır. Bir mutex nesnesi, yalnızca bir iş parçacığının kontrollü bir bölüme girmesine izin verir ve o bölüme erişmeye çalışan diğer iş parçacıklarını ilk iş parçacığı o bölümden çıkana kadar beklemeye zorlar.
Başka bir deyişle: Mutex = Mutually Exclusive Semaphore
Semafor Nedir (N belirtilen iş parçacığı):
Diyelim ki Shopper'ın 3 özdeş Dizüstü Bilgisayarı ve 3 özdeş anahtarı var. Semafor, free identical Laptop keys
sayısıdır. Semafor sayısı - anahtar sayısı - başlangıçta 3'e ayarlanır (üç Dizüstü Bilgisayarın tümü ücretsizdir), ardından Müşteri geldikçe sayım değeri düşürülür. Tüm Dizüstü Bilgisayarlar kullanımdaysa, yani boş anahtar kalmamışsa Dizüstü bilgisayar, semafor sayısı 0'dır. Artık herhangi bir müşteri Laptop'u iade ettiğinde, semafor 1'e (bir boş anahtar) yükseltilir ve sıradaki bir sonraki müşteriye verilir.
Official Definition
: “Bir semafor, paylaşılan bir kaynağın eşzamanlı kullanıcı sayısını maksimum sayıya kadar kısıtlar. İş parçacıkları kaynağa erişim talep edebilir (semaforu azaltarak) ve kaynağı kullanmayı bitirdiklerini (semaforu artırarak) bildirebilir.
Başka bir okumanız gerekir: Singleton ThreadSafe Örneğinin Tembel Oluşturulması
Örnek-1: (Aşağıdaki açıklama)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
package crunchify . com . tutorial ; import java . util . LinkedList ; import java . util . concurrent . Semaphore ; /** * @author Crunchify.com * */ public class CrunchifySemaphoreMutexTutorial { static Object crunchifyLock = new Object ( ) ; static LinkedList <String> crunchifyList = new LinkedList <String> ( ) ; // Semaphore maintains a set of permits. // Each acquire blocks if necessary until a permit is available, and then takes it. // Each release adds a permit, potentially releasing a blocking acquirer. static Semaphore semaphore = new Semaphore ( 0 ) ; static Semaphore mutex = new Semaphore ( 1 ) ; // I'll producing new Integer every time static class CrunchifyProducer extends Thread { public void run ( ) { int counter = 1 ; try { while ( true ) { String threadName = Thread . currentThread ( ) . getName ( ) + counter ++ ; mutex . acquire ( ) ; crunchifyList . add ( threadName ) ; System . out . println ( "Producer is prdoucing new value: " + threadName ) ; mutex . release ( ) ; // release lock semaphore . release ( ) ; Thread . sleep ( 500 ) ; } } catch ( Exception x ) { x . printStackTrace ( ) ; } } } // I'll be consuming Integer every stime static class CrunchifyConsumer extends Thread { String consumerName ; public CrunchifyConsumer ( String name ) { this . consumerName = name ; } public void run ( ) { try { while ( true ) { // acquire lock. Acquires the given number of permits from this semaphore, blocking until all are // available // process stops here until producer releases the lock semaphore . acquire ( ) ; // Acquires a permit from this semaphore, blocking until one is available mutex . acquire ( ) ; String result = "" ; for ( String value : crunchifyList ) { result = value + "," ; } System . out . println ( consumerName + " consumes value: " + result + "crunchifyList.size(): " + crunchifyList . size ( ) + "\n" ) ; mutex . release ( ) ; } } catch ( Exception e ) { e . printStackTrace ( ) ; } } } public static void main ( String [ ] args ) { new CrunchifyProducer ( ) . start ( ) ; new CrunchifyConsumer ( "Crunchify" ) . start ( ) ; new CrunchifyConsumer ( "Google" ) . start ( ) ; new CrunchifyConsumer ( "Yahoo" ) . start ( ) ; } } |
Yukarıdaki öğreticide CrunchifySemaphoreMutexTutorial.java
, CrunchifyProducer
crunchifyList
threadName
threadName eklediğinde semafor sinyali verebilir.
CrunchifyConsumer
daha sonra semaforu almaya çalışıyor olabilir, böylece CrunchifyProducer bir threadID'nin eklendiğini bildirene kadar bekleyecekler. Eklenen bir veriyi işaretledikten sonra, tüketicilerden biri uyandırılacak ve bir crunchifyList Nesnesini okuyabildiğini bilecektir. Bir listeyi okuyabilir, ardından semaforu elde etmeye çalışmaya geri dönebilir.
Bu süre içinde üretici başka bir paket yazdıysa, tekrar sinyal verdiyse ve tüketicilerden biri daha sonra başka bir paket okumaya devam edecekse ve bu böyle devam eder…
Başka bir deyişle:
1 2 3 |
CrunchifyProducer : Add an object o List - Semaphore . release ( 1 ) CrunchifyConsumer x N ) - Semaphore . acquire ( 1 ) - Read an object from List |

Sonuç:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Producer is prdoucing new value : Thread - 01 Crunchify consumes value : Thread - 01 , crunchifyList . size ( ) : 1 Producer is prdoucing new value : Thread - 02 Google consumes value : Thread - 02 , crunchifyList . size ( ) : 2 Producer is prdoucing new value : Thread - 03 Yahoo consumes value : Thread - 03 , crunchifyList . size ( ) : 3 Producer is prdoucing new value : Thread - 04 Crunchify consumes value : Thread - 04 , crunchifyList . size ( ) : 4 . . . . . . . . . . . . . . . |
Yarış durumu nasıl önlenir:
What if you have multiple Consumers?
Yukarıdaki Java Eğitiminde Tüketiciler (üretici değil), yarış koşullarını önlemek için paketi okurken (ancak semaforu alırken değil) arabelleği kilitlemelidir. Aşağıdaki örnekte, her şey aynı JVM'de olduğu için üretici de listeyi kilitler.
Örnek-2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
package crunchify . com . tutorial ; import java . util . concurrent . Semaphore ; /** * @author Crunchify.com * */ public class CrunchifyJavaSemaphoreTutorial { private static final int MAX_CONCURRENT_THREADS = 2 ; private final Semaphore crunchifyAdminLOCK = new Semaphore ( MAX_CONCURRENT_THREADS , true ) ; public void crunchifyStartTest ( ) { for ( int i = 0 ; i < 10 ; i ++ ) { CrunchifyPerson person = new CrunchifyPerson ( ) ; person . start ( ) ; } } public class CrunchifyPerson extends Thread { @Override public void run ( ) { try { // Acquire Lock crunchifyAdminLOCK . acquire ( ) ; } catch ( InterruptedException e ) { System . out . println ( "received InterruptedException" ) ; return ; } System . out . println ( "Thread " + this . getId ( ) + " start using Crunchify's car - Acquire()" ) ; try { sleep ( 1000 ) ; } catch ( Exception e ) { } finally { // Release Lock crunchifyAdminLOCK . release ( ) ; } System . out . println ( "Thread " + this . getId ( ) + " stops using Crunchify's car - Release()\n" ) ; } } public static void main ( String [ ] args ) { CrunchifyJavaSemaphoreTutorial test = new CrunchifyJavaSemaphoreTutorial ( ) ; test . crunchifyStartTest ( ) ; } } |
Sonuç:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Thread 11 start using Crunchify 's car - Acquire() Thread 10 start using Crunchify' s car - Acquire ( ) Thread 10 stops using Crunchify 's car - Release() Thread 12 start using Crunchify' s car - Acquire ( ) Thread 13 start using Crunchify 's car - Acquire() Thread 11 stops using Crunchify' s car - Release ( ) Thread 13 stops using Crunchify 's car - Release() Thread 15 start using Crunchify' s car - Acquire ( ) Thread 14 start using Crunchify 's car - Acquire() Thread 12 stops using Crunchify' s car - Release ( ) Thread 14 stops using Crunchify 's car - Release() Thread 16 start using Crunchify' s car - Acquire ( ) Thread 15 stops using Crunchify 's car - Release() Thread 17 start using Crunchify' s car - Acquire ( ) Thread 17 stops using Crunchify 's car - Release() Thread 18 start using Crunchify' s car - Acquire ( ) Thread 19 start using Crunchify 's car - Acquire() Thread 16 stops using Crunchify' s car - Release ( ) Thread 18 stops using Crunchify 's car - Release() Thread 19 stops using Crunchify' s car - Release ( ) |