Why this ReadWriteLock example dosen't work? - java

LinkedList throws exception when trying to poll data. But I think i correctly use read/write lock concept. What is wrong with that code?
package sample;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class PingPong extends Thread {
boolean read = false;
Queue<String> queue;
static ReadWriteLock lock = new ReentrantReadWriteLock();
final static Lock readLock = lock.readLock();
final static Lock writeLock = lock.writeLock();
boolean stop;
public PingPong(boolean read, Queue<String> queue) {
this.read = read;
this.queue = queue;
}
int count = 0;
#Override
public String toString() {
return "PingPong{" +
"read=" + read +
", count=" + count +
'}';
}
#Override
public void run() {
if (read) {
while (!stop) {
readLock.lock();
// synchronized (queue) {
try {
String string = queue.poll();
if (string != null) {
count++;
}
} finally {
readLock.unlock();
}
// }
inform();
}
} else {
while (!stop) {
writeLock.lock();
// synchronized (queue) {
try {
if (queue.add("some str" + count)) {
count++;
}
} finally {
writeLock.unlock();
}
// }
inform();
}
}
}
private void inform() {
// Thread.yield();
// synchronized (queue) {
// queue.notify();
// try {
// queue.wait(1);
// } catch (InterruptedException e) {
// e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
// }
// }
}
public static void main(String[] args) throws InterruptedException {
Queue<String> queue = new LinkedList();
// queue = new ArrayBlockingQueue<String>(100);
// queue = new ConcurrentLinkedQueue<String>();
List<PingPong> pongs = new ArrayList<PingPong>();
for (int i = 0; i < 10; ++i) {
PingPong pingPong = new PingPong(i % 2 == 0, queue);
pingPong.start();
pongs.add(pingPong);
}
Thread.sleep(1000);
int sum = 0;
int read = 0;
int write = 0;
for (PingPong pp : pongs) {
pp.stop = true;
pp.join();
}
for (PingPong pp : pongs) {
System.out.println(pp);
sum += pp.count;
if (pp.read) read += pp.count;
else write += pp.count;
}
System.out.println(sum);
System.out.println("write = " + write);
System.out.println("read = " + read);
System.out.println("queue.size() = " + queue.size());
System.out.println("balance (must be zero) = " + (write - read - queue.size()));
}
}

It's because this call mutates the queue collection:
String string = queue.poll();
From Queue JavaDoc:
Retrieves and removes the head of this queue, or returns null if this queue is empty.
Read locks are meant to be used in situations where multiple threads can safely read, while writes have to be performed exclusively (no other reads and writes). Because you are using read lock to poll the queue (write operation!), you are effectively allowing multiple threads to modify non thread-safe LinkedList concurrently.
Read-write lock isn't the correct synchronization mechanism in this case.

Related

Semaphore in Java. producer-consumer problem printer

package producerconsumer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Buffer {
int t;
private final Semaphore notEmptyy = new Semaphore(0); // prevent underflow
private final Semaphore notFulll = new Semaphore(10); // prevent overflow
private int itemn;
private int itemb;
int count=0;
int buffersize =10 ;
private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(buffersize);
private final Semaphore mutex = new Semaphore(1); // control buffer access
private final Semaphore notEmpty = new Semaphore(0); // prevent underflow
private final Semaphore notFull = new Semaphore(10); // prevent overflow
public Buffer(){
}
public void add( int x) throws InterruptedException{
while(count== buffersize )
notFulll.acquire();
System.out.println("user printer-request,: " +Thread.currentThread().getName() + " " + x);
queue.offer(x);
count++;
notEmptyy.release();
}
public int take() throws InterruptedException{
while(queue.isEmpty())
notEmptyy.acquire();
t=queue.take();
count--;
notFulll.release();
return t;
}
public void put( ){
while(true){
try {
Random random = new Random();
int data = random.nextInt(100);
notFull .acquire();
mutex .acquire();
add(data);
mutex .release();
notEmpty .release();
// itemb = data;
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
// System.out.println("user printer-request,: " +Thread.currentThread().getName() + " " + itemb);
// this.item = item;
}
}
public void get(){
while(true){
try{
notEmpty .acquire();
mutex .acquire();
itemn = take();
mutex .release();
notFull .release();
queue.remove(itemn);
System.out.println("print request, : "+Thread.currentThread().getName()+" " + itemn );
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
}
}
}
package producerconsumer;
public class producers implements Runnable{
private static final int DELAY = 500;
private Buffer osLabGroup;
public producers(Buffer buffer){
osLabGroup = buffer;
}
public void run(){
// while(true){
osLabGroup.put();
try{
Thread.sleep(DELAY);
}catch (InterruptedException exception) {}
}
}
package producerconsumer;
public class consumers implements Runnable{
private static final int DELAY = 1000;
private Buffer osLabGroup;
public consumers(Buffer buffer){
osLabGroup = buffer;
}
public void run(){
// while(true){
osLabGroup.get();
try{
Thread.sleep(DELAY);
}catch (InterruptedException exception) {}
}
}
//}
package producerconsumer;
public class ProducerConsumer {
public static void main(String[] args) {
Buffer buffer = new Buffer();
producers p1 = new producers(buffer);
consumers c1 = new consumers(buffer);
producers p2 = new producers(buffer);
consumers c2 = new consumers(buffer);
producers p3 = new producers(buffer);
consumers c3 = new consumers(buffer);
Thread pr1 = new Thread(p1);
Thread co1 = new Thread(c1);
Thread pr2 = new Thread(p2);
Thread co2 = new Thread(c2);
Thread pr3 = new Thread(p3);
Thread co3 = new Thread(c3);
pr1.setName("p1");
co1.setName("c1");
pr2.setName("p2");
co2.setName("c2");
pr3.setName("p3");
co3.setName("c3");
pr1.start();
co1.start();
pr2.start();
co2.start();
pr3.start();
co3.start();
}
}
I have a program that simulates the print jobs of a printer, one job at a time: either from Producer or Consumer and it shares an object called a Buffer.
in the buffer it has Set1 of threads, producers, put data with a ½ second delay.
also it does have a Set2 of threads, consumers, read data from the buffer with one second delay.
as it stands, I am trying to follow this guy https://www.youtube.com/watch?v=nxw2y27z0V4&t=1207s
using semaphore this is my code
I problem my output is not accurate enter image description here
this my edited code
package producerconsumer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Buffer {
int t;
private final Semaphore notEmptyy = new Semaphore(0); // prevent underflow
private final Semaphore notFulll = new Semaphore(10); // prevent overflow
private int itemn;
private int itemb;
int count=0;
int buffersize =10 ;
private final ArrayList<Integer> list = new ArrayList<Integer>(buffersize);
private final LinkedList<Integer> queue = new LinkedList<Integer>(list);
private final Semaphore mutex = new Semaphore(1); // control buffer access
private final Semaphore notEmpty = new Semaphore(0); // prevent underflow
private final Semaphore notFull = new Semaphore(10); // prevent overflow
public Buffer(){
}
public void add( int x) throws InterruptedException{
while(count== buffersize )
notFulll.acquire();
System.out.println("user printer-request,: " +Thread.currentThread().getName() + " " + x);
queue.offer(x);
count++;
notEmptyy.release();
}
public int take() throws InterruptedException{
while(count ==0)
notEmptyy.acquire();
t=queue.pollFirst();
count--;
notFulll.release();
return t;
}
public void put( ){
while(true){
try {
Random random = new Random();
int data = random.nextInt(100);
notFull.acquire();
mutex.acquire();
add(data);
mutex.release();
notEmpty.release();
// itemb = data;
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
// System.out.println("user printer-request,: " +Thread.currentThread().getName() + " " + itemb);
// this.item = item;
}
}
public void get(){
while(true){
try{
notEmpty.acquire();
mutex.acquire();
itemn = take();
mutex.release();
notFull.release();
// queue.remove(itemn);
System.out.println("print request, : "+Thread.currentThread().getName()+" " + itemn );
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
}
}
}
i get this output enter image description here
and this output enter image description here
In Buffer#get, when you take an item from queue, you call queue#remove again. This is a wrong behavior. You should consume this item instead of operating the queue outside of the concurrency control code. This can lead to abnormal behaviors, such as deadlock.
try {
notEmpty .acquire();
mutex .acquire();
itemn = take();
mutex .release();
notFull .release();
// why remove from queue again? It is already taken from queue. Comment this line
// queue.remove(itemn);
System.out.println("print request, : "+Thread.currentThread().getName()+" " + itemn );
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
In addition, in your program, you should replace ArrayBlockingQueue with a collection class under java.util package, such as LinkedList.
ArrayBlockingQueue you use is actually a thread-safe blocking queue. You can directly use take&put to complete this program without other concurrency control.
EDIT:
As mentioned in the video introduction, there are two ways to solve the producer-consumer problem, semaphore or monitor. Your code seems to mix these two together. There is no need to do any concurrency control in your add and take method.
Code should be:
public class consumers implements Runnable{
private static final int DELAY = 1000;
private Buffer osLabGroup;
public consumers(Buffer buffer){
osLabGroup = buffer;
}
public void run(){
while (true) {
osLabGroup.get();
try{
Thread.sleep(DELAY);
}catch (InterruptedException exception) {}
}
}
}
public class producers implements Runnable{
private static final int DELAY = 500;
private Buffer osLabGroup;
public producers(Buffer buffer){
osLabGroup = buffer;
}
public void run(){
while(true) {
osLabGroup.put();
try {
Thread.sleep(DELAY);
} catch (InterruptedException exception) {
}
}
}
}
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.Semaphore;
public class Buffer {
int buffersize =10 ;
private final LinkedList<Integer> queue = new LinkedList<Integer>();
private final Semaphore mutex = new Semaphore(1); // control buffer access
private final Semaphore notEmpty = new Semaphore(0); // prevent underflow
private final Semaphore notFull = new Semaphore(buffersize); // prevent overflow
public Buffer(){
}
public void add( int x) throws InterruptedException{
System.out.println("user printer-request,: " +Thread.currentThread().getName() + " " + x + "," + System.currentTimeMillis());
queue.add(x);
}
public int take() throws InterruptedException{
Integer first = queue.removeFirst();
System.out.println("print request, : "+Thread.currentThread().getName()+" " + first + "," + System.currentTimeMillis() );
return first;
}
public void put(){
try {
Random random = new Random();
int data = random.nextInt(100);
notFull.acquire();
mutex.acquire();
add(data);
mutex.release();
notEmpty.release();
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
}
public void get(){
try{
notEmpty.acquire();
mutex.acquire();
int take = take();
mutex.release();
notFull.release();
} catch (InterruptedException e){
System.out.println("InterruptedException caught ");
}
}
}

Java synchronized queue thread on producer and consumer

Java producer-consumer program using thread & synchronized queue, the program is separated into 3 classes but it couldn't be run.
Queue.java:
public class Queue {
static final int MAXQUEUE = 3;
int[] queue = new int[MAXQUEUE];
int front, rear;
public Queue(){ front = 0; rear = 0; }
public boolean isEmpty(){ return (front==rear); }
public boolean isFull(){
int index = rear+1 < MAXQUEUE ? rear+1 : 0;
return (index == front);
}
public void enqueue(int value) {
queue[rear] = value;
rear = rear+1 < MAXQUEUE ? rear+1 : 0;
}
public int dequeue(){
int data = queue[front];
front = front+1 < MAXQUEUE ? rear+1 : 0;
return data;
}
}
SynchronizedQueue.java:
import java.util.Queue;
public class SynchronizedQueue {
Queue queue;
public SynchronizedQueue() {queue = new Queue(); }
public synchronized void enqueue(int value) {
try {
while (queue.isFull()) {
System.out.println();
System.out.println("Queue is full, please wait....");
wait();
}
}
catch (InterruptedException e) { }
((SynchronizedQueue) queue).enqueue(value);
notify();
}
public synchronized int dequeue() {
try {
while (queue.isEmpty()) {
System.out.println();
System.out.println("Queue is empty, please wait....");
wait();
}
}
catch ( InterruptedException e ) { }
int data = ((SynchronizedQueue) queue).dequeue();
notify();
return data;
}
}
Main program Ch10_3.java:
class Producer extends Thread {
public int count = 0;
public void run() {
int value;
while ( Ch10_3.isRunning ) {
value = (int)(Math.random()*100);
Ch10_3.squeue.enqueue(value);
System.out.print(">" + value + "]");
count++;
try {
Thread.sleep((int)(Math.random()*100));
}
catch( InterruptedException e) { }
}
System.out.println("\n" + Thread.currentThread() + "Producer thread end.");
}
}
class Consumer extends Thread {
public int count = 0;
public void run() {
int data;
while (Ch10_3.isRunning) {
data = Ch10_3.squeue.dequeue();
System.out.println("[" + data + ">");
count++;
try {
Thread.sleep((int)(Math.random()*100));
}
catch( InterruptedException e) { }
}
System.out.println("\n" + Thread.currentThread() + "Consumer thread end.");
}
}
public class Ch10_3 {
static final int MAXITEMS = 10;
static SynchonizedQueue squeue = new SynchronizedQueue();
static boolean isRunning = true;
public static void main(String[] args) {
Producer producer = new Producer();
Consumer consumer = new Consumer();
producer.start(); consumer.start();
while (true)
if (producer.count >= MAXITEMS && producer.count == consumer.count)
{ isRunning = false; break; }
}
}
Error message:
Exception in thread "main" java.lang.Error: Unresolved compilation
problem: at Ch10_3.main(Ch10_3.java:41)
In the catch blocks from enqueue and dequeue methods form class SynchronizedQueue you are trying to cast the queue member attribute which is of type Queue, to SynchronizedQueue.
In SynchronizedQueue.enqueue() we have:
((SynchronizedQueue) queue).enqueue(value);
Since there is no relation between Queue and SynchronizedQueue the compiler gives a compilation error. You should remove the cast.
But the best solution is to just use a java.util.concurrent.BlockingQueue implementation available in JAVA SDK, which will handle all the synchronisation part for you.

Java Semaphore Acquire Order Based on Thread Value

Good afternoon everyone,
I am working on a school project that requires me to use semaphores to control access to resources. From what I have developed so far, they are:
Semaphore 1) Waiting Area - This permits only 15 customers (Threads) to enter the waiting area, else they are rejected from the store (using TryAcquire).
Semaphore 2) ServerQueue - This permits customers (Threads) to use the only 3 servers in the restaurant once in the waiting area.
My Problem: Our professor requires the serverQueue to take the shortest order (IE, the thread with the least amount of burritosOrdered) when in the waitingArea.
Full flow of application:
Main method instantiates a serverQueue (3 servers) and a waitingArea (15 customers)
Main method instantiates and starts 20 customer threads
Each customer (Thread) run function has been overridden to attempt to get in the waiting area
Each customer in the waitingArea tries to access a server in the serverQueue
How can I tell the serverQueue to get the shortest order? Because the threads override the run, I don't have direct access to an array of all the threads to compare their values.
Thank you for taking a look!
Main
public class Main {
private static final int numCustomers = 5;
public static void main(String[] args)
{
ServerQueue serverQueue = new ServerQueue();
WaitingArea waitingArea = new WaitingArea(3, serverQueue);
Thread customers[] = new Thread[numCustomers];
for (int i = 0; i < numCustomers; i++)
{
customers[i] = new Thread(new Customer(waitingArea), "Customer " + i);
}
for (int i = 0; i < numCustomers; i++)
{
customers[i].start();
}
}
}
Customer
import java.util.Date;
import java.util.Random;
// Runnable is an interface that facilitates threads
public class Customer implements Runnable {
// The semaphore
// private ServerQueue serverQueue;
private WaitingArea waitingArea;
public int burritosOrdered;
public int burritosMade = 0;
// Constructor, allow semaphore to be passed/assigned
public Customer(WaitingArea waitingArea) {
this.waitingArea = waitingArea;
Random r = new Random();
this.burritosOrdered = r.nextInt(21);
}
public void setBurritosMade(int newBurritos) {
this.burritosMade += newBurritos;
}
// We must override the run function within Runnable
// The run function is called by threadObject.start();
#Override
public void run() {
waitingArea.seatCustomer(burritosOrdered);
}
}
waitingArea
import java.util.Date;
import java.util.concurrent.Semaphore;
public class WaitingArea {
private Semaphore semaphore;
private ServerQueue serverQueue;
private int maxCustomers;
public WaitingArea(int maxCustomers, ServerQueue serverQueue) {
semaphore = new Semaphore(maxCustomers, true);
this.serverQueue = serverQueue;
this.maxCustomers = maxCustomers;
}
public void seatCustomer(int burritosOrdered)
{
boolean hasPermit = false;
try
{
hasPermit = semaphore.tryAcquire();
if(hasPermit) {
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " entered store ordering "
+ burritosOrdered + " burritos");
serverQueue.finishOrder();
} else {
System.out.println(new Date() + " - " + Thread.currentThread().getName() + " left due to full shop");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(hasPermit) {
semaphore.release();
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " left with " + burritosOrdered + " burritos made");
}
}
}
}
serverQueue
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ServerQueue {
// This Semaphore will keep track of no. of servers used at any point.
private final Semaphore semaphore;
// While checking/acquiring a free server out of three available servers, we will use this lock.
private final Lock serverLock;
// This array represents the pool of free server.
private boolean freeServers[];
public ServerQueue() {
semaphore = new Semaphore(1, true);
freeServers = new boolean[1];
serverLock = new ReentrantLock();
// Set all servers to available
for(int i=0;i<freeServers.length;i++) {
freeServers[i] = true;
}
}
public void finishOrder() throws InterruptedException {
try {
System.out.println(semaphore.getClass());
// Decrease the semaphore counter to mark a printer busy
semaphore.acquire();
// Get the server printer
int assignedServer = getServer();
Thread.sleep(3000);
// Print the job
System.out.println(new Date() + " - " + Thread.currentThread().getName()
+ " is getting service from server " + assignedServer);
//Server is done; Free the server to be used by other threads.
releaseServer(assignedServer);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.print(new Date() + " - " + Thread.currentThread().getName() + " has been served\n");
//Increase the semaphore counter back
semaphore.release();
}
}
//Acquire a free server to finish a job
private int getServer() {
int foundServer = -1;
try {
//Get a lock here so that only one thread can go beyond this at a time
serverLock.lock();
//Check which server is free
for (int i=0; i<freeServers.length; i++)
{
//If free server found then mark it busy
if (freeServers[i])
{
foundServer = i;
freeServers[i] = false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//Allow other threads to check for free servers
serverLock.unlock();
}
return foundServer;
}
//Release the server
private void releaseServer(int i) {
serverLock.lock();
//Mark the server as free
freeServers[i] = true;
serverLock.unlock();
}
}

Having one thread acquire multiple objects from a shared list

I have a list of available employees, categorized by their profession (e.g "Programmer", "Tester"),
the amount of each available profession is stored in a Semaphore.
To accomplish a certain task - each done in a different thread - a list of professions if given (e.g. 2 "Programmer", 1 "Manager")
and the task should get them in an all or nothing fashion - if all are available you take all the ones in the list, otherwise wait for everyone to be available.
I have accomplished this by limiting the access for the list itself using BlockingQueue, Semaphore or just lock it manually.
What I'm asking is what is the proper way to do it, and if possible, how to still have the release method be available to other threads.
You need a monitor (http://en.wikipedia.org/wiki/Monitor_%28synchronization%29) to accomplish your task.
It can be realized with a java.util.concurrent.Lock (ReentrantLock) and many Condition's on the lock.
Your problem really got my interest. Quite a fun project. Here's a basic implementation that seems to work for your description. See the bottom for a runnable example to go along with it. It's fairly limited (doesn't support negative acquires, no timeout options, etc etc), but it has just enough to use it, and you could easily extend upon it as necessary.
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Semaphore;
/** Represents a group of semaphores identified by distinct strings
* Supports basic acquire and release operations. Other operations could be added as necessary
* #author MPatashnik
*/
public class SemaphoreGroup {
/** The total number of permits available to this, as it was constructed */
private final HashMap<String, Integer> permits;
/** The semaphores in this group, by their identifier */
private final HashMap<String, Semaphore> semaphores;
/** The semaphore monitoring use of operations in this SemaphoreGroup */
private final Semaphore operationLock;
/** A map of threads to permits they currently own */
private final HashMap<Thread, Map<String, Integer>> threads;
/** Set to true to see printing output of threads acquiring and releasing */
private static final boolean DEBUG = false;
/** Creates a SemaphoreGroup. All semaphores are initialized as unfair.
* #param permits - the Number of permits for each identifier string
*/
public SemaphoreGroup(Map<String, Integer> permits) {
this.permits = new HashMap<String, Integer>(permits);
operationLock = new Semaphore(1);
semaphores = new HashMap<String, Semaphore>();
threads = new HashMap<Thread, Map<String, Integer>>();
for(String s : permits.keySet()){
semaphores.put(s, new Semaphore(permits.get(s)));
}
}
/** Attempts to acquire the given permits
* #param permits - the permits to acquire
* #throws InterruptedException - see Semaphore.acquire()
* #throws IllegalArgumentException - If one of the permits this wants to
* acquire is an unrecognized string, or any of the
* permit acquisition counts is negative
*/
public void acquire(Map<String, Integer> permits)
throws InterruptedException, IllegalArgumentException{
try{
operationLock.acquire();
if(DEBUG) System.out.println("Acquired " + Thread.currentThread().getName());
for(Map.Entry<String, Integer> e : permits.entrySet()){
Semaphore s = semaphores.get(e.getKey());
if(s == null){
throw new IllegalArgumentException("Illegal Permit Name " + e.getKey() + " Not in " + this);
}
if(e.getValue() < 0)
throw new IllegalArgumentException("Illegal Permit Value " + e.getValue() + " Must be positive");
if(s.availablePermits() < e.getValue()){
operationLock.release();
if(DEBUG) System.out.println("Released " + Thread.currentThread().getName());
//Not enough permits - wait on semaphore until someone releases, then try again
synchronized(operationLock){
operationLock.wait();
}
acquire(permits);
return;
}
}
//All semaphores ok. Do acquiring and exit
for(Map.Entry<String, Integer> e : permits.entrySet()){
semaphores.get(e.getKey()).acquire(e.getValue());
}
Thread t = Thread.currentThread();
//Update information of this thread owning permits
Map<String, Integer> currentlyOwned = threads.get(t);
if(currentlyOwned == null){
threads.put(t, new HashMap<String, Integer>(permits));
}
else{
HashMap<String, Integer> totalOwned = new HashMap<String, Integer>(permits);
for(Map.Entry<String, Integer> e : permits.entrySet()){
totalOwned.put(e.getKey(),
e.getValue()
+ (totalOwned.get(e.getKey()) == null ? 0 : currentlyOwned.get(e.getKey())));
}
threads.put(t, totalOwned);
}
}
finally{
operationLock.release();
if(DEBUG) System.out.println("Released " + Thread.currentThread().getName());
}
}
/** Attempts to release the given amounts of the given permits.
* Won't release more permits for any identifier than this currently owns.
* #param permits - the permits to release.
* #throws InterruptedException - see Semaphore.acquire
*/
public void release(Map<String, Integer> permits) throws InterruptedException{
try{
operationLock.acquire();
if(DEBUG) System.out.println("Acquired " + Thread.currentThread().getName());
Thread t = Thread.currentThread();
//Check to see if this thread has any permits at all
if(! threads.containsKey(t))
return;
for(Map.Entry<String, Integer> e : permits.entrySet()){
Semaphore s = semaphores.get(e.getKey());
if(s == null){
throw new IllegalArgumentException("Illegal Permit Name " + e.getKey() + " Not in " + this);
}
int has = threads.get(t).containsKey(e.getKey()) ? threads.get(t).get(e.getKey()) : 0;
int toRemove = Math.min(e.getValue(), has);
s.release(toRemove);
threads.get(t).put(e.getKey(), has - toRemove);
}
if(DEBUG){
System.out.println("\nReleasing " + t);
System.out.println(threads.toString().replaceAll("},", "}\n"));
}
//Ok, notify a thread wanting to acquire
synchronized(operationLock){
operationLock.notify();
}
}finally{
operationLock.release();
if(DEBUG) System.out.println("Released " + Thread.currentThread().getName());
}
}
/** Releases all permits this currently owns for all identifiers within this Semaphore Group
* #throws InterruptedException - see Semaphore.acquire
*/
public void releaseAll() throws InterruptedException{
try{
operationLock.acquire();
if(DEBUG) System.out.println("Acquired " + Thread.currentThread().getName());
Thread t = Thread.currentThread();
if(! threads.containsKey(t)) return;
HashMap<String, Integer> permits = new HashMap<String, Integer>(threads.get(t));
operationLock.release();
if(DEBUG) System.out.println("Released " + Thread.currentThread().getName());
release(permits);
}finally{
operationLock.release();
if(DEBUG) System.out.println("Released " + Thread.currentThread().getName());
}
}
/** Returns the permits (by identifier) this SemaphoreGroup still has available. */
public Map<String, Integer> getAvailablePermits(){
HashMap<String, Integer> available = new HashMap<>();
for(Entry<String, Semaphore> e : semaphores.entrySet()){
available.put(e.getKey(), e.getValue().availablePermits());
}
return available;
}
/** Returns the set of valid identifying strings for this semaphore group */
public Set<String> getIdentifyingStrings(){
return semaphores.keySet();
}
/** Returns the available permits out of the total as the toString */
#Override
public String toString(){
Map<String, Integer> available = getAvailablePermits();
String s = "{";
for(Entry<String, Integer> e : permits.entrySet()){
s += e.getKey() + "=" + available.get(e.getKey()) + "/" + e.getValue() + ", ";
}
return s.substring(0, s.length() - 2) + "}";
}
}
Runnable companion:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashMap;
import java.util.LinkedList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ThreadRunner extends JFrame {
private static LinkedList<Worker> threads;
private static SemaphoreGroup semaphore;
private static HashMap<String, Integer> totalPermits;
public ThreadRunner(){
setLayout(new BorderLayout());
add(new InfoPanel(), BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
repaint();
setVisible(true);
}
static class InfoPanel extends JPanel{
public InfoPanel(){
setPreferredSize(new Dimension(600, 500));
}
#Override
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setFont(new Font("Arial", Font.PLAIN, 15));
int x = 20;
int y = 20;
g2d.drawString("Available: " + semaphore.toString(), x, y);
y += 50;
for(Worker t : threads){
if(t.working) g2d.setColor(Color.RED);
else g2d.setColor(Color.BLACK);
g2d.drawString(t.getName() + "-" + t.status + " : " + t.job.toString(), x, y);
y += 25;
if(! t.working) g2d.drawString("Next: " + t.nextJob.toString(), x + 150, y);
y += 35;
}
}
}
static class Worker extends Thread{
private volatile String status;
private boolean working;
private HashMap<String, Integer> job = new HashMap<>();
private HashMap<String, Integer> nextJob = new HashMap<>();
private int jobIndex;
private static final int WORK_TIME = 2000;
public Worker(int i){
super("Worker " + i);
jobIndex = 1;
}
#Override
public void run(){
try{
createNextJob();
while(true){
createNextJob();
HashMap<String, Integer> aJob = nextJob;
semaphore.acquire(aJob);
job = aJob;
working = true;
for(int i = 0; i < 10; i++){
Thread.sleep(WORK_TIME / 10);
status = ((i + 1) * 10) + "% done of Job " + jobIndex;
}
semaphore.releaseAll();
working = false;
job.clear();
jobIndex++;
}
} catch (InterruptedException e) {}
}
private void createNextJob(){
nextJob = new HashMap<>();
nextJob.put("Bronze", (int)(totalPermits.get("Bronze") * Math.random()));
nextJob.put("Silver", (int)(totalPermits.get("Silver") * Math.pow(Math.random(), 2)));
nextJob.put("Gold", (int)(totalPermits.get("Gold") * Math.pow(Math.random(), 3)));
nextJob.put("Platinum", (int)(totalPermits.get("Platinum") * Math.pow(Math.random(), 4)));
}
#Override
public String toString(){
return getName();
}
}
public static void main(String[] args){
totalPermits = new HashMap<>();
totalPermits.put("Bronze", 15);
totalPermits.put("Silver", 10);
totalPermits.put("Gold", 5);
totalPermits.put("Platinum", 2);
semaphore = new SemaphoreGroup(totalPermits);
threads = new LinkedList<Worker>();
final int NUMB_WORKERS = 5;
for(int i = 0; i < NUMB_WORKERS; i++){
threads.add(new Worker(i));
}
ThreadRunner tr = new ThreadRunner();
//Start worker threads
for(Worker w : threads){
w.start();
}
//Monitor gui in main thread
while(true){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
tr.repaint();
}
}
}
Here's a complete, working, contrived example that I believe fulfills the outlined requirements.
It tracks the total number of resources available in Semaphores, the actual resources in BlockingQueues and tasks in BlockingQueues.
If it's unable to acquire the required resources for a task immediately, it resubmits the task to the back of the Queue (this could be done other ways, but in this example it's using a bounded thread pool of workers so you wouldn't necessarily want them to wait until the resources are available as this could potentially prevent parallelization of other tasks that may be able to run immediately)
package so.thread.resources;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class MultiResourcesMain {
public static int numManagers = 5;
public static int numProgrammers = 15;
public static int numTesters = 5;
public static Semaphore managersLease = new Semaphore(numManagers);
public static Semaphore programmersLease = new Semaphore(numProgrammers);
public static Semaphore testersLease = new Semaphore(numTesters);
public static BlockingQueue<Manager> managers = new LinkedBlockingQueue<Manager>();
public static BlockingQueue<Programmer> programmers = new LinkedBlockingQueue<Programmer>();
public static BlockingQueue<Tester> testers = new LinkedBlockingQueue<Tester>();
public static Random rand = new Random();
public static BlockingQueue<Task> tasks = new LinkedBlockingQueue<>();
public static Object resourceLock = new Object();
public static AtomicBoolean running = new AtomicBoolean(true);
public static AtomicInteger tasksRun = new AtomicInteger(0);
public static AtomicInteger resubmits = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
// prime the resources
for (int i = 0; i < numManagers; i++) {
managers.add(new Manager());
}
for (int i = 0; i < numProgrammers; i++) {
programmers.add(new Programmer());
}
for (int i = 0; i < numTesters; i++) {
testers.add(new Tester());
}
int numTasks = 100;
int managersRandLimit = numManagers + 1;
int programmersRandLimit = numProgrammers + 1;
int testersRandLimit = numTesters + 1;
// generate tasks to execute with random resource requirements
for (int i = 0; i < numTasks; i++) {
tasks.add(new Task(UUID.randomUUID().toString(), new TaskResources(rand.nextInt(managersRandLimit), rand.nextInt(programmersRandLimit), rand.nextInt(testersRandLimit))));
}
// spin up worker threads
int numWorkers = 10;
ExecutorService taskExecutor = Executors.newFixedThreadPool(numWorkers);
for (int i = 0; i < numWorkers; i++) {
taskExecutor.submit(new Worker());
}
while (tasksRun.get() < numTasks) {
Thread.sleep(10);
}
running.set(false);
taskExecutor.shutdown();
taskExecutor.awaitTermination(2, TimeUnit.SECONDS);
System.out.println(String.format("Done, ran %d tasks and resubmitted %d tasks due to insufficient resources at acquire time", tasksRun.get(), resubmits.get()));
}
public static class Worker implements Runnable {
#Override
public void run() {
while (running.get()) {
try {
Task task = tasks.poll(1, TimeUnit.SECONDS);
if (null != task) {
if (acquireResources(task.resources)) {
runTask(task);
releaseResources(task.resources);
} else {
// couldn't execute task now, returning to task queue
System.out.println(String.format("[%s :: %s] !!! Couldn't acquire resources for Task %s, resubmitting",
Thread.currentThread().getName(), new Date(), task.id));
tasks.add(task);
resubmits.getAndIncrement();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(String.format("[%s :: %s] >>> Thread shutdown",
Thread.currentThread().getName(), new Date()));
}
}
public static void runTask(Task task) {
Date now = new Date();
long elapsed = now.getTime() - task.created.getTime();
System.out.println(String.format("[%s :: %s] *** Running task with %d managers, %d programmers & %d testers, waited %d millis to execute for id %s",
Thread.currentThread().getName(), now, task.resources.managers, task.resources.programmers, task.resources.testers, elapsed, task.id));
tasksRun.getAndIncrement();
}
public static void releaseResources(TaskResources res) {
synchronized (resourceLock) {
managersLease.release(res.managers);
programmersLease.release(res.programmers);
testersLease.release(res.testers);
}
}
public static boolean acquireResources(TaskResources res) {
synchronized (resourceLock) {
boolean acquiredManagers = false;
boolean acquiredProgrammers = false;
boolean acquiredTesters = false;
acquiredManagers = managersLease.tryAcquire(res.managers);
if (acquiredManagers) {
acquiredProgrammers = programmersLease.tryAcquire(res.programmers);
if (acquiredProgrammers) {
acquiredTesters = testersLease.tryAcquire(res.testers);
}
}
if (acquiredManagers && acquiredProgrammers && acquiredTesters) {
return true;
} else {
// return unused resources
if (acquiredProgrammers) {
programmersLease.release(res.programmers);
}
if (acquiredManagers) {
managersLease.release(res.managers);
}
return false;
}
}
}
public abstract static class Person {
}
public static class Manager extends Person {
}
public static class Programmer extends Person {
}
public static class Tester extends Person {
}
public static class Task {
public String id;
public TaskResources resources;
public Date created = new Date();
public Task(String id, TaskResources resources) {
this.id = id;
this.resources = resources;
}
}
public static class TaskResources {
public int managers;
public int programmers;
public int testers;
public TaskResources(int managers, int programmers, int testers) {
this.managers = managers;
this.programmers = programmers;
this.testers = testers;
}
}
}

producer - consumer multithreading in Java

I want to write program using multithreading wait and notify methods in Java.
This program has a stack (max-length = 5). Producer generate number forever and put it in the stack, and consumer pick it from stack.
When stack is full producer must wait and when stack is empty consumers must wait.
The problem is that it runs just once, I mean once it produce 5 number it stops but i put run methods in while(true) block to run nonstop able but it doesn't.
Here is what i tried so far.
Producer class:
package trail;
import java.util.Random;
import java.util.Stack;
public class Thread1 implements Runnable {
int result;
Random rand = new Random();
Stack<Integer> A = new Stack<>();
public Thread1(Stack<Integer> A) {
this.A = A;
}
public synchronized void produce()
{
while (A.size() >= 5) {
System.out.println("List is Full");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result = rand.nextInt(10);
System.out.println(result + " produced ");
A.push(result);
System.out.println(A);
this.notify();
}
#Override
public void run() {
System.out.println("Producer get started");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
produce();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the consumer:
package trail;
import java.util.Stack;
public class Thread2 implements Runnable {
Stack<Integer> A = new Stack<>();
public Thread2(Stack<Integer> A) {
this.A = A;
}
public synchronized void consume() {
while (A.isEmpty()) {
System.err.println("List is empty" + A + A.size());
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.err.println(A.pop() + " Consumed " + A);
this.notify();
}
#Override
public void run() {
System.out.println("New consumer get started");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
consume();
}
}
}
and here is the main method:
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
Thread1 thread1 = new Thread1(stack);// p
Thread2 thread2 = new Thread2(stack);// c
Thread A = new Thread(thread1);
Thread B = new Thread(thread2);
Thread C = new Thread(thread2);
A.start();
B.start();
C.start();
}
I think it will be better for understanding and dealing with synchronisation in general if you try to separate three things which are currently mixed:
Task which is going to do the actual job. Names for classes Thread1 & Thread2 are misleading. They are not Thread objects, but they are actually jobs or tasks implementing Runnable interface you are giving to Thread objects.
Thread object itself which you are creating in main
Shared object which encapsulates synchronised operations/logic on a queue, a stack etc. This object will be shared between tasks. And inside this shared object you will take care of add/remove operations (either with synchronized blocks or synchronized methods). Currently (as it was pointed out already), synchronization is done on a task itself (i.e. each task waits and notifies on its own lock and nothing happens). When you separate concerns, i.e. let one class do one thing properly it will eventually become clear where is the problem.
Your consumer and you producer are synchronized on different objects and do not block each other. If this works, I daresay it's accidental.
Read up on java.util.concurrent.BlockingQueue and java.util.concurrent.ArrayBlockingQueue. These provide you with more modern and easier way to implement this pattern.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
You should synchronize on the stack instead of putting it at the method level try this code.
Also don't initalize the stack in your thread classes anyways you are passing them in the constructor from the main class, so no need of that.
Always try to avoid mark any method with synchronized keyword instead of that try to put critical section of code in the synchronized block because the more size of your synchronized area more it will impact on performance.
So, always put only that code into synchronized block that need thread safety.
Producer Code :
public void produce() {
synchronized (A) {
while (A.size() >= 5) {
System.out.println("List is Full");
try {
A.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result = rand.nextInt(10);
System.out.println(result + " produced ");
A.push(result);
System.out.println("stack ---"+A);
A.notifyAll();
}
}
Consumer Code :
public void consume() {
synchronized (A) {
while (A.isEmpty()) {
System.err.println("List is empty" + A + A.size());
try {
System.err.println("wait");
A.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.err.println(A.pop() + " Consumed " + A);
A.notifyAll();
}
}
Try this:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CircularArrayQueue<T> {
private volatile Lock rwLock = new ReentrantLock();
private volatile Condition emptyCond = rwLock.newCondition();
private volatile Condition fullCond = rwLock.newCondition();
private final int size;
private final Object[] buffer;
private volatile int front;
private volatile int rare;
/**
* #param size
*/
public CircularArrayQueue(int size) {
this.size = size;
this.buffer = new Object[size];
this.front = -1;
this.rare = -1;
}
public boolean isEmpty(){
return front == -1;
}
public boolean isFull(){
return (front == 0 && rare == size-1) || (front == rare + 1);
}
public void enqueue(T item){
try {
// get a write lock
rwLock.lock();
// if the Q is full, wait the write lock
if(isFull())
fullCond.await();
if(rare == -1){
rare = 0;
front = 0;
} else if(rare == size - 1){
rare = 0;
} else {
rare ++;
}
buffer[rare] = item;
//System.out.println("Added\t: " + item);
// notify the reader
emptyCond.signal();
} catch(InterruptedException e){
e.printStackTrace();
} finally {
// unlock the write lock
rwLock.unlock();
}
}
public T dequeue(){
T item = null;
try{
// get the read lock
rwLock.lock();
// if the Q is empty, wait the read lock
if(isEmpty())
emptyCond.await();
item = (T)buffer[front];
//System.out.println("Deleted\t: " + item);
if(front == rare){
front = rare = -1;
} else if(front == size - 1){
front = 0;
} else {
front ++;
}
// notify the writer
fullCond.signal();
} catch (InterruptedException e){
e.printStackTrace();
} finally{
// unlock read lock
rwLock.unlock();
}
return item;
}
}
You can use Java's awesome java.util.concurrent package and its classes.
You can easily implement the producer consumer problem using the
BlockingQueue. A BlockingQueue already supports operations that wait
for the queue to become non-empty when retrieving an element, and wait
for space to become available in the queue when storing an element.
Without BlockingQueue, every time we put data to queue at the producer
side, we need to check if queue is full, and if full, wait for some
time, check again and continue. Similarly on the consumer side, we
would have to check if queue is empty, and if empty, wait for some
time, check again and continue. However with BlockingQueue we don’t
have to write any extra logic than to just add data from Producer and
poll data from Consumer.
Read more From:
http://javawithswaranga.blogspot.in/2012/05/solving-producer-consumer-problem-in.html
http://www.javajee.com/producer-consumer-problem-in-java-using-blockingqueue
use BlockingQueue,LinkedBlockingQueue this was really simple.
http://developer.android.com/reference/java/util/concurrent/BlockingQueue.html
package javaapplication;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ProducerConsumer {
public static Object lock = new Object();
public static Stack stack = new Stack();
public static void main(String[] args) {
Thread producer = new Thread(new Runnable() {
int i = 0;
#Override
public void run() {
do {
synchronized (lock) {
while (stack.size() >= 5) {
try {
lock.wait();
} catch (InterruptedException e) {
}
}
stack.push(++i);
if (stack.size() >= 5) {
System.out.println("Released lock by producer");
lock.notify();
}
}
} while (true);
}
});
Thread consumer = new Thread(new Runnable() {
#Override
public void run() {
do {
synchronized (lock) {
while (stack.empty()) {
try {
lock.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ProdCons1.class.getName()).log(Level.SEVERE, null, ex);
}
}
while(!stack.isEmpty()){
System.out.println("stack : " + stack.pop());
}
lock.notifyAll();
}
} while (true);
}
});
producer.start();
consumer.start();
}
}
Have a look at this code example:
import java.util.concurrent.*;
import java.util.Random;
public class ProducerConsumerMulti {
public static void main(String args[]){
BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();
Thread prodThread = new Thread(new Producer(sharedQueue,1));
Thread consThread1 = new Thread(new Consumer(sharedQueue,1));
Thread consThread2 = new Thread(new Consumer(sharedQueue,2));
prodThread.start();
consThread1.start();
consThread2.start();
}
}
class Producer implements Runnable {
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
private Random rng;
public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
this.threadNo = threadNo;
this.sharedQueue = sharedQueue;
this.rng = new Random();
}
#Override
public void run() {
while(true){
try {
int number = rng.nextInt(100);
System.out.println("Produced:" + number + ":by thread:"+ threadNo);
sharedQueue.put(number);
Thread.sleep(100);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
this.sharedQueue = sharedQueue;
this.threadNo = threadNo;
}
#Override
public void run() {
while(true){
try {
int num = sharedQueue.take();
System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
Thread.sleep(100);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
Notes:
Started one Producer and two Consumers as per your problem statement
Producer will produce random numbers between 0 to 100 in infinite loop
Consumer will consume these numbers in infinite loop
Both Producer and Consumer share lock free and Thread safe LinkedBlockingQueue which is Thread safe. You can remove wait() and notify() methods if you use these advanced concurrent constructs.
Seems like you skipped something about wait(), notify() and synchronized.
See this example, it should help you.

Categories