Apa itu Java Semaphore dan Mutex – Java Concurrency MultiThread dijelaskan dengan Contoh
Diterbitkan: 2015-03-12Java Concurrency adalah topik yang sangat luas. Ada ratusan tutorial dan contoh yang tersedia untuk digunakan. Beberapa waktu yang lalu saya telah menulis beberapa tutorial tentang Jalankan Beberapa Utas Secara Bersamaan di Java dan berbagai jenis Blok yang Disinkronkan.
Dalam tutorial ini kita akan membahas:
- Penjelasan Mutex
- Penjelasan Semaphore
- Dua Contoh dengan detail
Mari kita mulai
Let's keep this in mind
saat membaca penjelasan di bawah ini:
- Ambil contoh Pembeli dan Pelanggan
- Pembeli meminjam Laptop
- Pelanggan dapat datang dan menggunakan Laptop – pelanggan memerlukan kunci untuk menggunakan Laptop
- Setelah digunakan – pelanggan dapat mengembalikan Laptop ke Shopper
Apa itu Mutex (Hanya 1 utas):
Pembeli memiliki kunci untuk Laptop. Satu pelanggan dapat memiliki kunci – meminjam Laptop – pada saat itu. Ketika tugas selesai, Shopper memberikan (membebaskan) kunci ke pelanggan berikutnya dalam antrian.
Official Definition
:
“Mutex biasanya digunakan untuk membuat serial akses ke bagian re-entrant code
yang cannot be executed concurrently
oleh lebih dari satu utas. Objek mutex hanya mengizinkan satu utas ke bagian yang dikontrol, memaksa utas lain yang mencoba mendapatkan akses ke bagian itu untuk menunggu hingga utas pertama keluar dari bagian itu.
Dengan kata lain: Mutex = Mutually Exclusive Semaphore
Apa itu Semaphore (N utas yang ditentukan):
Katakanlah sekarang Shopper memiliki 3 Laptop identik dan 3 kunci identik. Semaphore adalah jumlah free identical Laptop keys
. Hitungan semaphore – hitungan kunci – disetel ke 3 di awal (ketiga Laptop gratis), kemudian nilai hitungan dikurangi saat Pelanggan masuk. Jika semua Laptop sedang digunakan, yaitu tidak ada kunci kosong yang tersisa untuk Laptop, jumlah semaphore adalah 0. Sekarang, ketika salah satu pelanggan mengembalikan Laptop, semaphore ditingkatkan menjadi 1 (satu kunci gratis), dan diberikan kepada pelanggan berikutnya dalam antrian.
Official Definition
: “Semaphore membatasi jumlah pengguna simultan dari sumber daya bersama hingga jumlah maksimum. Utas dapat meminta akses ke sumber daya (mengurangi semaphore), dan dapat memberi sinyal bahwa mereka telah selesai menggunakan sumber daya (menambah semaphore).
Yang lain harus dibaca: Pembuatan Lazy dari Singleton ThreadSafe Instance
Contoh-1: (Penjelasan di bawah)
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 ( ) ; } } |
Dalam tutorial di atas CrunchifySemaphoreMutexTutorial.java
ketika CrunchifyProducer
menambahkan threadName
ke objek crunchifyList
linkedList, ia dapat memberi sinyal semaphore.
CrunchifyConsumer
kemudian dapat mencoba untuk mendapatkan semaphore sehingga mereka akan menunggu sampai CrunchifyProducer memberi sinyal bahwa threadID telah ditambahkan. Setelah memberi sinyal data tambahan, salah satu konsumen akan dibangunkan dan akan mengetahui bahwa ia dapat membaca Obyek crunchifyList. Itu dapat membaca daftar, lalu kembali mencoba memperoleh di semaphore.
Jika pada saat itu produsen telah menulis paket lain, ia telah memberi sinyal lagi dan salah satu dari konsumen akan melanjutkan untuk membaca paket lain dan seterusnya…
Dengan kata lain:
1 2 3 |
CrunchifyProducer : Add an object o List - Semaphore . release ( 1 ) CrunchifyConsumer x N ) - Semaphore . acquire ( 1 ) - Read an object from List |

Hasil:
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 . . . . . . . . . . . . . . . |
Cara mencegah kondisi balapan:
What if you have multiple Consumers?
Dalam Tutorial Java di atas Konsumen (bukan produsen) harus mengunci buffer saat membaca paket (tetapi tidak saat memperoleh semaphore) untuk mencegah kondisi balapan. Pada contoh di bawah, produser juga mengunci daftar karena semuanya berada di JVM yang sama.
Contoh-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 ( ) ; } } |
Hasil:
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 ( ) |