Besides the common synchronize which is based in the lock bit that every Java object has, you have more sophisticated synchronizers in java, such as:
- Semaphore – Use the concept of a permit to indicate a max number of allowed threads in a place. When you use the value 1, the behavior its similar to synchronize, also called binary semaphore. There is however a big difference here, you acquire a permit on the semaphore, not a locking object, its just a variable to count when a thread acquires a permit and when a thread releases a permit, some kind of a counter. The only thing you really have are threads locking until a permit be available. In the example below, we define 3 as the number of permits, so after 3 acquires the 4 thread will wait for a release before continue its execution.
12345678910 <span class="rem">// Define the semaphore to control 3 permits. </span><span class="rem">// 3 Threads can acquire the <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">mySemaphore</span> </span>Semaphore <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">mySemaphore</span> = <span class="kwrd">new</span> Semaphore<span class="GINGER_SOFATWARE_correct">(</span>3, <span class="kwrd">true</span>);<span class="rem">// 3 threads can execute this line of code. The 4 thread must wait for a release</span><span class="GINGER_SOFATWARE_correct">mySemaphore</span><span class="GINGER_SOFATWARE_correct">.</span>acquire<span class="GINGER_SOFATWARE_correct">(</span>);<span class="rem">// .. <span class="GINGER_SOFATWARE_correct">somewhere</span> in the <span class="GINGER_SOFATWARE_correct">code a thread</span> releases the <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">mySemaphore</span>, </span><span class="rem">// <span class="GINGER_SOFATWARE_correct">and</span> now the next waiting thread can acquire</span><span class="GINGER_SOFATWARE_correct">mySemaphore</span><span class="GINGER_SOFATWARE_correct">.</span>release<span class="GINGER_SOFATWARE_correct">(</span>);
- CountDownLatch – Initialize this class with a number (to countdown), and when reaches 0 the thread waiting unblocks and follows its way. (After the await the latch cannot be reused)
123456789101112131415 <span class="rem">// Initializes a countdown starting from 3</span>CountDownLatch latch = <span class="kwrd">new</span> CountDownLatch<span class="GINGER_SOFATWARE_correct">(</span>3);<span class="rem">// ... <span class="GINGER_SOFATWARE_correct">other</span> threads are running... </span><span class="rem">// Some thread blocks and waits for the latch countdown </span><span class="rem">// <span class="GINGER_SOFATWARE_correct">to</span> reach "0"</span><span class="GINGER_SOFATWARE_correct">latch</span><span class="GINGER_SOFATWARE_correct">.</span>await<span class="GINGER_SOFATWARE_correct">(</span>);<span class="rem">// ... <span class="GINGER_SOFATWARE_correct">code</span>, methods, other objects... <span class="GINGER_SOFATWARE_correct">etc.</span>..</span><span class="rem">// ... <span class="GINGER_SOFATWARE_correct">at</span> some place the OTHER threads do the countdown, </span><span class="rem">// <span class="GINGER_SOFATWARE_correct">decrementing</span> the latch.. <span class="GINGER_SOFATWARE_correct">when</span> it <span class="GINGER_SOFATWARE_correct">reachs</span> 0 </span><span class="rem">// <span class="GINGER_SOFATWARE_correct">the</span> blocked thread with the "await<span class="GINGER_SOFATWARE_correct">(</span>)" follows its way</span><span class="GINGER_SOFATWARE_correct">latch</span><span class="GINGER_SOFATWARE_correct">.</span><span class="GINGER_SOFATWARE_correct">countDown</span><span class="GINGER_SOFATWARE_correct">(</span>);
- CyclicBarrier – This class behaves somehow as the inverse of the CountDownLatch. After N await() the threads blocked can follow their way. (A CyclicBarrier can be reused)
12345678 <span class="rem">// 3 threads must <span class="GINGER_SOFATWARE_correct">await</span> before can unblock</span><span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">CyclicBarrier</span> barrier = <span class="kwrd">new</span> CyclicBarrier<span class="GINGER_SOFATWARE_correct">(</span>3);<span class="rem">// <span class="GINGER_SOFATWARE_correct">threads</span> they block here until the 3 is reached</span><span class="GINGER_SOFATWARE_correct">barrier</span><span class="GINGER_SOFATWARE_correct">.</span>await<span class="GINGER_SOFATWARE_correct">(</span>);<span class="rem">// <span class="GINGER_SOFATWARE_correct">after</span> 3 threads in await this code will run!</span>System<span class="GINGER_SOFATWARE_correct">.</span><span class="kwrd">out</span><span class="GINGER_SOFATWARE_correct">.</span><span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">println</span><span class="GINGER_SOFATWARE_correct">(</span>"Thank you to the 3 friends who <span class="GINGER_SOFATWARE_correct">awaited</span> <span class="kwrd">for</span> me!”);
- Phaser – Very complex synchronizer, a mix of CountDownLatch and CyclicBarrier, with lots of customized options. If you need a behavior similar to 2 previous synchronizers but they were not enough you want to deep into this one. It behaves like a CyclicBarrier but you can register a set of threads and at any time deregister, achieving a level of customization not possible with the other synchronizers. Think about the need to wait for threads to arrive before you can continue or start another set of tasks. More information about this at Oracle website:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html
123456789101112131415161718192021 <span class="kwrd"><span class="GINGER_SOFATWARE_correct">void</span></span> <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">runTasks</span><span class="GINGER_SOFATWARE_correct">(</span>List<Runnable> tasks) {<span class="rem">// Initialize the <span class="GINGER_SOFATWARE_correct">phaser</span>, "1" to register self</span><span class="GINGER_SOFATWARE_correct">final</span> Phaser phaser = <span class="kwrd">new</span> Phaser<span class="GINGER_SOFATWARE_correct">(</span>1);<span class="rem">// <span class="GINGER_SOFATWARE_correct">create</span> and start threads</span><span class="kwrd"><span class="GINGER_SOFATWARE_correct">for</span></span> (final Runnable task : tasks) {<span class="rem">// <span class="GINGER_SOFATWARE_correct">register</span> here</span><span class="GINGER_SOFATWARE_correct">phaser</span><span class="GINGER_SOFATWARE_correct">.</span>register<span class="GINGER_SOFATWARE_correct">(</span>);<span class="kwrd"><span class="GINGER_SOFATWARE_correct">new</span></span> Thread<span class="GINGER_SOFATWARE_correct">(</span>) {<span class="kwrd"><span class="GINGER_SOFATWARE_correct">public</span></span> <span class="kwrd">void</span> run<span class="GINGER_SOFATWARE_correct">(</span>) {<span class="rem">// <span class="GINGER_SOFATWARE_correct">await</span> all creation</span><span class="GINGER_SOFATWARE_correct">phaser</span><span class="GINGER_SOFATWARE_correct">.</span><span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">arriveAndAwaitAdvance</span><span class="GINGER_SOFATWARE_correct">(</span>);<span class="GINGER_SOFATWARE_correct">task</span><span class="GINGER_SOFATWARE_correct">.</span>run<span class="GINGER_SOFATWARE_correct">(</span>);}}<span class="GINGER_SOFATWARE_correct">.</span><span class="GINGER_SOFATWARE_correct">start</span><span class="GINGER_SOFATWARE_correct">(</span>);}<span class="rem">// <span class="GINGER_SOFATWARE_correct">allow</span> threads to start and <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">deregister</span> self</span><span class="GINGER_SOFATWARE_correct">phaser</span><span class="GINGER_SOFATWARE_correct">.</span><span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">arriveAndDeregister</span><span class="GINGER_SOFATWARE_correct">(</span>);}
- Exchanger – The best explanation comes from Oracle doc itself: “A synchronization point at which threads can pair and swap elements within pairs”. One thread wants to send information to other thread and blocks awaiting to send the data, and in EXCHANGE receives what the other thread wants to send too! This behavior happens to both sides!
1234567891011121314151617181920 <span class="rem">// Create the <span class="GINGER_SOFATWARE_correct">exchanger</span>. </span><span class="rem">// We choose String as the data <span class="GINGER_SOFATWARE_noSuggestion GINGER_SOFATWARE_correct">datatype</span> </span><span class="GINGER_SOFATWARE_correct">Exchanger</span><String> ex = <span class="kwrd">new</span> Exchanger<String>();<span class="rem">//</span><span class="rem">// .... Somewhere at Thread 1, </span><span class="rem">//</span><span class="rem">// I will block until I can send str1 to Thread 2, and receive a value too!</span>String str1 = <span class="str">"value to send from Thread 1 to Thread 2"</span>;String valueReturnedFromThread2 = ex<span class="GINGER_SOFATWARE_correct">.</span>exchange<span class="GINGER_SOFATWARE_correct">(</span>str1);<span class="rem">//</span><span class="rem">// ... Somewhere at Thread 2,</span><span class="rem">//</span><span class="rem">// I will block until I can send str2 to Thread 1</span><span class="rem">// I will receive a value from Thread 1 too!</span>String str2 = <span class="str">"value to send to Thread 1 from Thread 2"</span>;String valueReturnedFromThread1 = ex<span class="GINGER_SOFATWARE_correct">.</span>exchange<span class="GINGER_SOFATWARE_correct">(</span>str2);
1
1