I ran into the problem that every time the program will stop executing when the producer fill all the places in the arraylist buffer. But, theoretically. the consumer process could still get into the get() function, cause the notEmpty semaphore got the signal value up to 10 now. So the producer process could still work after the consumer process release the signal value back to the semaphore notFull.
But it just stop, and I can't find out the problem.
Here is the program:
import java.util.List;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Semaphore;
/**
* A bounded buffer maintains a fixed number of "slots". Items can be
* inserted into and removed from the buffer. The buffer has a maximum
* size.
*/
class BoundedBuffer2
{
// the maximum size of the bounded buffer
final public static int MAXSIZE = 10;
Semaphore notEmpty = new Semaphore(0);
Semaphore notFull = new Semaphore(MAXSIZE);
Semaphore sema = new Semaphore(1);
// the buffer
volatile List<Integer> buffer;
public BoundedBuffer2()
{
buffer = new ArrayList<Integer>();
}
// add an element to the end of the buffer if it is not full
public synchronized void put(int input)
throws InterruptedException
{
notFull.acquire();
sema.acquire();
buffer.add(input);
sema.release();
notEmpty.release();
}
// take an element from the front of the buffer
public synchronized int get()
throws InterruptedException
{
notEmpty.acquire();
sema.acquire();
int result = buffer.remove(0);
sema.release();
notFull.release();
return result;
}
public int size()
{
int result = buffer.size();
return result;
}
}
/**
* An instance of the Producer class produces new integers at random
* intervals, and inserts them into a bounded buffer.
*/
class Producer2 extends Thread
{
// the buffer in which to insert new integers
BoundedBuffer2 buffer;
public Producer2(BoundedBuffer2 buffer)
{
this.buffer = buffer;
}
public void run()
{
Random random = new Random();
try {
while (true) {
Thread.sleep(100);
//insert a random integer
int next = random.nextInt();
buffer.put(next);
System.err.println("b.size() increases to " + buffer.size());
}
}
catch (InterruptedException e) {}
}
}
/**
* An instance of the Consumer class consumes integers from a bounded
* buffer at random intervals.
*/
class Consumer2 extends Thread
{
// the buffer in which to insert new integers
BoundedBuffer2 buffer;
public Consumer2(BoundedBuffer2 buffer)
{
this.buffer = buffer;
}
public void run()
{
Random random = new Random();
try {
while (true) {
Thread.sleep(200);
//get the next integer from the buffer
int next = buffer.get();
System.err.println("next = " + next);
System.err.println("b.size() reducted to " + buffer.size());
}
}
catch (InterruptedException e) {}
}
}
public class UseBuffer2
{
public static void main(String [] args)
{
BoundedBuffer2 buffer = new BoundedBuffer2();
Producer2 p = new Producer2(buffer);
Consumer2 c = new Consumer2(buffer);
p.start();
c.start();
}
}
and Here is the output to console:
b.size() increases to 1
b.size() increases to 2
next = 400524264
b.size() reducted to 1
b.size() increases to 2
b.size() increases to 3
next = 241523118
b.size() reducted to 2
b.size() increases to 3
next = -1618289090
b.size() reducted to 2
b.size() increases to 3
b.size() increases to 4
next = -316455080
b.size() reducted to 3
b.size() increases to 4
b.size() increases to 5
next = 338682909
b.size() reducted to 4
b.size() increases to 5
b.size() increases to 6
next = -961276708
b.size() reducted to 5
b.size() increases to 6
b.size() increases to 7
next = 2056804692
b.size() reducted to 6
b.size() increases to 7
b.size() increases to 8
next = -301063524
b.size() reducted to 7
b.size() increases to 8
b.size() increases to 9
next = -148582342
b.size() reducted to 8
b.size() increases to 9
b.size() increases to 10
next = -2076430410
b.size() reducted to 9
b.size() increases to 10
Read how synchronized keyword works: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html
The relevant part:
it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.