Updated code example and test case for mutex (#7642)

This commit is contained in:
Kamlesh Kumar 2019-08-25 21:13:47 +05:30 committed by maibin
parent 58595acd6f
commit 1888614f84
7 changed files with 45 additions and 38 deletions

View File

@ -1,11 +1,12 @@
package com.baeldung.concurrent.mutex; package com.baeldung.concurrent.mutex;
public class SequenceGenerator { public class SequenceGenerator {
private int currentValue = 0; private int currentValue = 0;
public int getNextSequence() throws InterruptedException { public int getNextSequence() {
currentValue = currentValue + 1; currentValue = currentValue + 1;
Thread.sleep(500);
return currentValue; return currentValue;
} }
} }

View File

@ -4,15 +4,16 @@ import com.google.common.util.concurrent.Monitor;
public class SequenceGeneratorUsingMonitor extends SequenceGenerator { public class SequenceGeneratorUsingMonitor extends SequenceGenerator {
private Monitor monitor = new Monitor(); private Monitor mutex = new Monitor();
@Override @Override
public int getNextSequence() throws InterruptedException { public int getNextSequence() {
monitor.enter(); mutex.enter();
try { try {
return super.getNextSequence(); return super.getNextSequence();
} finally { } finally {
monitor.leave(); mutex.leave();
} }
} }
} }

View File

@ -7,7 +7,7 @@ public class SequenceGeneratorUsingReentrantLock extends SequenceGenerator {
private ReentrantLock mutex = new ReentrantLock(); private ReentrantLock mutex = new ReentrantLock();
@Override @Override
public int getNextSequence() throws InterruptedException { public int getNextSequence() {
try { try {
mutex.lock(); mutex.lock();
return super.getNextSequence(); return super.getNextSequence();
@ -15,4 +15,5 @@ public class SequenceGeneratorUsingReentrantLock extends SequenceGenerator {
mutex.unlock(); mutex.unlock();
} }
} }
} }

View File

@ -7,12 +7,15 @@ public class SequenceGeneratorUsingSemaphore extends SequenceGenerator {
private Semaphore mutex = new Semaphore(1); private Semaphore mutex = new Semaphore(1);
@Override @Override
public int getNextSequence() throws InterruptedException { public int getNextSequence() {
try { try {
mutex.acquire(); mutex.acquire();
return super.getNextSequence(); return super.getNextSequence();
} catch (InterruptedException e) {
throw new RuntimeException("Exception in critical section.", e);
} finally { } finally {
mutex.release(); mutex.release();
} }
} }
} }

View File

@ -2,9 +2,11 @@ package com.baeldung.concurrent.mutex;
public class SequenceGeneratorUsingSynchronizedBlock extends SequenceGenerator { public class SequenceGeneratorUsingSynchronizedBlock extends SequenceGenerator {
private Object mutex = new Object();
@Override @Override
public int getNextSequence() throws InterruptedException { public int getNextSequence() {
synchronized (this) { synchronized (mutex) {
return super.getNextSequence(); return super.getNextSequence();
} }
} }

View File

@ -3,7 +3,7 @@ package com.baeldung.concurrent.mutex;
public class SequenceGeneratorUsingSynchronizedMethod extends SequenceGenerator { public class SequenceGeneratorUsingSynchronizedMethod extends SequenceGenerator {
@Override @Override
public synchronized int getNextSequence() throws InterruptedException { public synchronized int getNextSequence() {
return super.getNextSequence(); return super.getNextSequence();
} }

View File

@ -1,7 +1,7 @@
package com.baeldung.concurrent.mutex; package com.baeldung.concurrent.mutex;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@ -12,59 +12,58 @@ import java.util.concurrent.TimeUnit;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import com.baeldung.concurrent.mutex.SequenceGenerator;
import com.baeldung.concurrent.mutex.SequenceGeneratorUsingMonitor;
import com.baeldung.concurrent.mutex.SequenceGeneratorUsingReentrantLock;
import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSemaphore;
import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSynchronizedBlock;
import com.baeldung.concurrent.mutex.SequenceGeneratorUsingSynchronizedMethod;
public class MutexUnitTest { public class MutexUnitTest {
private final int RANGE = 30; // @Test
// This test verifies the race condition use case, it may pass or fail based on execution environment
@Test // Uncomment @Test to run it
public void givenUnsafeSequenceGenerator_whenRaceCondition_thenUnexpectedBehavior() throws Exception { public void givenUnsafeSequenceGenerator_whenRaceCondition_thenUnexpectedBehavior() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGenerator()); int count = 1000;
Assert.assertNotEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGenerator(), count);
Assert.assertNotEquals(count, uniqueSequences.size());
} }
@Test @Test
public void givenSequenceGeneratorUsingSynchronizedMethod_whenRaceCondition_thenSuccess() throws Exception { public void givenSequenceGeneratorUsingSynchronizedMethod_whenRaceCondition_thenSuccess() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSynchronizedMethod()); int count = 1000;
Assert.assertEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGeneratorUsingSynchronizedMethod(), count);
Assert.assertEquals(count, uniqueSequences.size());
} }
@Test @Test
public void givenSequenceGeneratorUsingSynchronizedBlock_whenRaceCondition_thenSuccess() throws Exception { public void givenSequenceGeneratorUsingSynchronizedBlock_whenRaceCondition_thenSuccess() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSynchronizedBlock()); int count = 1000;
Assert.assertEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGeneratorUsingSynchronizedBlock(), count);
Assert.assertEquals(count, uniqueSequences.size());
} }
@Test @Test
public void givenSequenceGeneratorUsingReentrantLock_whenRaceCondition_thenSuccess() throws Exception { public void givenSequenceGeneratorUsingReentrantLock_whenRaceCondition_thenSuccess() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingReentrantLock()); int count = 1000;
Assert.assertEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGeneratorUsingReentrantLock(), count);
Assert.assertEquals(count, uniqueSequences.size());
} }
@Test @Test
public void givenSequenceGeneratorUsingSemaphore_whenRaceCondition_thenSuccess() throws Exception { public void givenSequenceGeneratorUsingSemaphore_whenRaceCondition_thenSuccess() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingSemaphore()); int count = 1000;
Assert.assertEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGeneratorUsingSemaphore(), count);
Assert.assertEquals(count, uniqueSequences.size());
} }
@Test @Test
public void givenSequenceGeneratorUsingMonitor_whenRaceCondition_thenSuccess() throws Exception { public void givenSequenceGeneratorUsingMonitor_whenRaceCondition_thenSuccess() throws Exception {
Set<Integer> uniqueSequences = getASetOFUniqueSequences(new SequenceGeneratorUsingMonitor()); int count = 1000;
Assert.assertEquals(RANGE, uniqueSequences.size()); Set<Integer> uniqueSequences = getUniqueSequences(new SequenceGeneratorUsingMonitor(), count);
Assert.assertEquals(count, uniqueSequences.size());
} }
private Set<Integer> getASetOFUniqueSequences(SequenceGenerator generator) throws Exception { private Set<Integer> getUniqueSequences(SequenceGenerator generator, int count) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3); ExecutorService executor = Executors.newFixedThreadPool(3);
Set<Integer> uniqueSequences = new HashSet<>(); Set<Integer> uniqueSequences = new LinkedHashSet<>();
List<Future<Integer>> futures = new ArrayList<>(); List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < RANGE; i++) { for (int i = 0; i < count; i++) {
futures.add(executor.submit(generator::getNextSequence)); futures.add(executor.submit(generator::getNextSequence));
} }
@ -72,7 +71,7 @@ public class MutexUnitTest {
uniqueSequences.add(future.get()); uniqueSequences.add(future.get());
} }
executor.awaitTermination(15, TimeUnit.SECONDS); executor.awaitTermination(1, TimeUnit.SECONDS);
executor.shutdown(); executor.shutdown();
return uniqueSequences; return uniqueSequences;