I'm trying to implement Producer and Consumer problem by using semaphores
in java. The issue is when I start two threads (Producer and Consumer) consumer doesn't start and producer blocks itself after buffer is full. I mean it looks like there is only one thread which works in synchronous manner. Thus, as I mentioned I use 3 semaphores which are empty, full, and mutex. Here is the simplest code;
Producer class;
import java.util.concurrent.Semaphore;
public class Producer implements Runnable {
private Semaphore empty;
private Semaphore full;
private Semaphore mutex;
public Producer(Semaphore empty, Semaphore full, Semaphore mutex) {
this.empty = empty;
this.full = full;
this.mutex = mutex;
}
@Override
public void run() {
while (true) {
try {
empty.acquire();
mutex.acquire();
Thread.sleep(500);
System.out.println("Producer producess an element");
mutex.release();
full.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Consumer class;
import java.util.concurrent.Semaphore;
public class Consumer implements Runnable {
private Semaphore empty;
private Semaphore full;
private Semaphore mutex;
public Consumer(Semaphore empty, Semaphore full, Semaphore mutex) {
this.empty = empty;
this.full = full;
this.mutex = mutex;
}
@Override
public void run() {
while (true) {
try {
full.acquire();
mutex.acquire();
Thread.sleep(500);
System.out.println("Consumer consumes an element");
mutex.release();
empty.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ProducerConsumerExample class
import java.util.concurrent.Semaphore;
public class ProducerConsumerProblem {
private Semaphore empty;
private Semaphore full;
private Semaphore mutex;
public ProducerConsumerProblem(int empty, int full) {
this.empty = new Semaphore(empty);
this.full = new Semaphore(full);
this.mutex = new Semaphore(1);
}
public void runProducerConsumerExample() {
Producer producer = new Producer(empty, full, mutex);
Consumer consumer = new Consumer(empty, full, mutex);
Thread p = new Thread(producer);
Thread c = new Thread(consumer);
p.run();
c.run();
}
}
And finally test class
import org.junit.Before;
import org.junit.Test;
public class ProducerConsumerProblemTest {
private ProducerConsumerProblem testClass;
private static final int EMPTY = 10;
private static final int FULL = 0;
@Before
public void setUp() {
testClass = new ProducerConsumerProblem(EMPTY, FULL);
}
@Test
public void testName() {
testClass.runProducerConsumerExample();
}
}
Output:
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
Producer producess an element
After 10 items produced nothing happens and thread gets blocked.
Don't use
run()
, usestart()
should be
Calling
run()
doesn't generate a new thread of execution. It merely runs the functionality within the current thread of execution.See this question/answer for more details.
Note also that I would shutdown the threads properly at the end of your test run (otherwise you'll build up multiple threads as you add/run tests). Interrupt your threads or set a volatile boolean indicating that your loops should complete.