ما هو Java Semaphore و Mutex - وأوضح Java Concurrency MultiThread مع المثال
نشرت: 2015-03-12يعد التزامن جافا موضوعًا واسعًا جدًا. هناك المئات من البرامج التعليمية والأمثلة المتاحة للاستخدام. في بعض الوقت ، كتبت بعض البرامج التعليمية حول تشغيل خيوط متعددة بشكل متزامن في Java وأنواع مختلفة من الكتل المتزامنة.
في هذا البرنامج التعليمي سوف ننتقل إلى ما يلي:
- شرح موتكس
- شرح السيمافور
- مثالان مع التفاصيل
هيا بنا نبدأ
Let's keep this in mind
أثناء قراءة الشرح أدناه:
- خذ مثالا على المتسوق والعميل
- المتسوق يستعير أجهزة الكمبيوتر المحمولة
- يمكن للعميل القدوم واستخدام الكمبيوتر المحمول - يحتاج العميل إلى مفتاح لاستخدام الكمبيوتر المحمول
- بعد الاستخدام - يمكن للعميل إعادة الكمبيوتر المحمول إلى Shopper
ما هو موتكس (خيط واحد فقط):
المتسوق لديه مفتاح لجهاز كمبيوتر محمول. يمكن لعميل واحد الحصول على المفتاح - استعارة كمبيوتر محمول - في ذلك الوقت. عند انتهاء المهمة ، يعطي المتسوق (يحرر) المفتاح للعميل التالي في قائمة الانتظار.
Official Definition
:
"يستخدم كائن المزامنة عادةً في إجراء تسلسل للوصول إلى قسم من re-entrant code
الذي cannot be executed concurrently
بأكثر من مؤشر ترابط واحد. يسمح كائن كائن المزامنة (mutex) بخيط واحد فقط في قسم متحكم فيه ، مما يجبر الخيوط الأخرى التي تحاول الوصول إلى هذا القسم على الانتظار حتى خروج سلسلة الرسائل الأولى من هذا القسم. "
بمعنى آخر: Mutex = Mutually Exclusive Semaphore
ما هو سيمافور (ن المواضيع المحددة):
لنفترض الآن أن لدى Shopper 3 أجهزة كمبيوتر محمولة متطابقة و 3 مفاتيح متطابقة. Semaphore هو عدد free identical Laptop keys
. تم تعيين عدد الإشارات - عدد المفاتيح - على 3 في البداية (جميع أجهزة الكمبيوتر المحمولة الثلاثة مجانية) ، ثم تنخفض قيمة العد عندما يأتي العميل. إذا كانت جميع أجهزة الكمبيوتر المحمولة قيد الاستخدام ، أي لا توجد مفاتيح مجانية متبقية لـ الكمبيوتر المحمول ، عدد الإشارات هو 0. الآن ، عندما يقوم أي عميل بإرجاع الكمبيوتر المحمول ، يتم زيادة الإشارة إلى 1 (مفتاح مجاني واحد) ، ويتم إعطاؤها للعميل التالي في قائمة الانتظار.
Official Definition
: "الإشارة تقيد عدد المستخدمين المتزامنين لمورد مشترك بحد أقصى. يمكن أن تطلب الخيوط الوصول إلى المورد (تقليل الإشارة) ، ويمكن أن تشير إلى أنها انتهيت من استخدام المورد (بزيادة الإشارة). "
يجب قراءة آخر: Lazy Creation of Singleton ThreadSafe Instance
مثال 1: (الشرح أدناه)
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 ( ) ; } } |
في البرنامج التعليمي أعلاه CrunchifySemaphoreMutexTutorial.java
عندما يضيف CrunchifyProducer
threadName
إلى كائن crunchifyList
المرتبط ، فإنه يمكن أن يشير إلى الإشارة.
يمكن بعد ذلك أن يحاول CrunchifyConsumer
الحصول على الإشارة لذلك سينتظرون حتى يقوم CrunchifyProducer بالإشارة إلى إضافة threadID. عند الإشارة إلى بيانات مضافة ، سيتم إيقاظ أحد المستهلكين وسيعرف أنه يمكنه قراءة كائن crunchifyList. يمكنه قراءة قائمة ، ثم العودة إلى محاولة الحصول على الإشارة.
إذا كتب المنتج في ذلك الوقت حزمة أخرى ، فقد أشار مرة أخرى وسيقوم أي من المستهلكين بعد ذلك بقراءة حزمة أخرى وما إلى ذلك ...
بعبارات أخرى:
1 2 3 |
CrunchifyProducer : Add an object o List - Semaphore . release ( 1 ) CrunchifyConsumer x N ) - Semaphore . acquire ( 1 ) - Read an object from List |

نتيجة:
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 . . . . . . . . . . . . . . . |
كيفية منع حالة السباق:
What if you have multiple Consumers?
في شرح Java التعليمي أعلاه ، يجب على المستهلكين (وليس المنتجين) قفل المخزن المؤقت عند قراءة الحزمة (ولكن ليس عند الحصول على الإشارة) لمنع ظروف السباق. في المثال أدناه ، يقوم المنتج أيضًا بتأمين القائمة نظرًا لأن كل شيء موجود على نفس JVM.
المثال 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 ( ) ; } } |
نتيجة:
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 ( ) |