How do I achieve thread safety in following code - java

I'm reading about thread safety and synchronized keyword, but I'm stuck figuring out how it's implemented correctly.
I have a scenario where Thread A saves data to a Buffer while Thread B reads the data and saves it to the database.
How can I achieve thread safety with the following code?
By thread safety I mean Thread B wont start until Thread A finished it's job and same applies to Thread A.
public class Main {
public static void main(String args[]) throws InterruptedException {
LinkedBlockingQueue<Document> queue = new LinkedBlockingQueue<>();
ProducerThread mProducer = new ProducerThread(queue);
ConsumerThread mConsumer = new ConsumerThread(queue);
new Thread(mProducer).start();
new Thread(mConsumer).start();
}
}
--
public class ProducerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
public ProducerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
#Override
public void run() {
while(true) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
try {
queue.put(document);
System.out.println("Document added " + document.toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
--
public class ConsumerThread implements Runnable {
private LinkedBlockingQueue<Document> queue;
private Database mDatabase;
public ConsumerThread(LinkedBlockingQueue<Document> queue) {
this.queue = queue;
}
#Override
public void run() {
try {
Document doc;
mDatabase = Database.getInstance();
if (Client.isAlive()) {
while (queue.take() != null) {
mDatabase.insert(queue.take());
// Thread.sleep(10);
System.out.println("Document consumed " + queue.take().toString());
if (!Client.isAlive()) {
wait();
Client.reconnect();
}
}
} else {
wait();
}
} catch(InterruptedException | IllegalMonitorStateException e){
e.printStackTrace();
}
}
}
I get the following output
> Document added{{timeAdded=2018-04-22 13:20:27.88}}
> Document{{timeAdded=2018-04-22 13:20:27.88}} Document added
> Document{{timeAdded=2018-04-22 13:20:28.881}} Document added
> Document{{timeAdded=2018-04-22 13:20:29.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:30.882}} Consumed
> Document{{timeAdded=2018-04-22 13:20:30.882}} Document added
> Document{{timeAdded=2018-04-22 13:20:31.883}} Document added
> Document{{timeAdded=2018-04-22 13:20:32.883}} Consumed
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:33.884}} Document added
> Document{{timeAdded=2018-04-22 13:20:34.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:35.885}} Document added
> Document{{timeAdded=2018-04-22 13:20:36.886}} Consumed
> Document{{timeAdded=2018-04-22 13:20:36.886}} Document added

I don't know if this helps, but I would write a third class called ProductionProcess or something like that...
Short additional explanation: The ProductionClass holds the queue which stores the single Document objects. The Producer thread starts to "produce" objects as long as the queue (At the moment size of 10) is full. Whenever a slot in this queue gets free because the Consumer thread removed a Document object. The Producer thread receives a signal and starts "producing" Document objects again until the queue is full. The complete source code should be thread-safe.
public class ProductionProcess
{
private static final int CAPACITY;
private final Queue QUEUE;
private final Lock LOCK;
private final Condition BUFFER_FULL;
private final Condition BUFFER_EMPTY;
static
{
CAPACITY = 10;
}
ProductionProcess()
{
this.QUEUE = new LinkedList <Document> ();
this.LOCK = new ReentrantLock();
this.BUFFER_FULL = this.LOCK.newCondition();
this.BUFFER_EMPTY = this.LOCK.newCondition();
}
public void produce() throws InterruptedException
{
this.LOCK.lock();
try
{
while(ProductionProcess.CAPACITY == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is full, waiting!");
this.BUFFER_FULL.await();
}
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
Document document = new Document("timeAdded", timestamp);
if(true == this.QUEUE.offer(document))
{
System.out.printf("Added to queue: " + document);
this.BUFFER_EMPTY.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
public void receive() throws InterruptedException
{
this.LOCK.lock();
try
{
Database mDatabase = Database.getInstance();
while(0 == this.QUEUE.size())
{
System.out.println(Thread.currentThread().getName() + " : Buffer is empty, waiting!");
this.BUFFER_EMPTY.await();
}
Document mDocument = (Document) this.QUEUE.poll());
if(null != mDocument)
{
mDatabase.insert(mDocument);
System.out.printf("Consumed from queue: " + document);
System.out.println(Thread.currentThread().getName() + " : Signalling that buffer may be empty now");
this.BUFFER_FULL.signalAll();
}
}
finally
{
this.LOCK.unlock();
}
}
}
After that use it like this...
ProductionProcess process = new ProductionProcess();
Runnable runnableProducer = new Runnable() {
#Override public void run()
{
while(true)
{
try
{
process.produce();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
Runnable runnableConsumer = new Runnable() {
#Override public void run()
{
while(true)
{
try
{
process.receive();
Thread.sleep(1000);
}
catch(InterruptedException exc)
{
exc.printStackTrace();
}
}
}
}
new Thread(runnableProducer).start();
new Thread(runnableConsumer).start();
I don't test it extensive but it should work. If it doesn't work just comment it...
Moreover its not my code if you can speak german watch this link.

Related

Java concurrent deadlock

Run the Main.main() method seems like a deadlock has occurred.
I found out it can be fixed if replace notify() with notifyAll().
But why?
Shouldn't the worst case always be called Lazy Thread to another Lazy Thread?
public class Main {
public static void main(String[] args) {
Table table = new Table(3);
new MakerThread("MakerThread-1", table, 8931415L).start();
new MakerThread("MakerThread-2", table, 314144L).start();
new MakerThread("MakerThread-3", table, 42131415L).start();
new EaterThread("EaterThread-1", table, 6313L).start();
new EaterThread("EaterThread-2", table, 8536313L).start();
new EaterThread("EaterThread-3", table, 35256313L).start();
new LazyThread("LazyThread-1", table).start();
new LazyThread("LazyThread-2", table).start();
new LazyThread("LazyThread-3", table).start();
new LazyThread("LazyThread-4", table).start();
new LazyThread("LazyThread-5", table).start();
new LazyThread("LazyThread-6", table).start();
new LazyThread("LazyThread-7", table).start();
}
}
public class Table {
private final String[] buffer;
private int tail;
private int head;
private int count;
public Table(int count) {
this.buffer = new String[count];
this.tail = 0;
this.head = 0;
this.count = 0;
}
public synchronized void put(String cake) throws InterruptedException {
while (count >= buffer.length) {
wait();
}
System.out.println(Thread.currentThread().getName() + " puts " + cake);
buffer[tail] = cake;
tail = (tail + 1) % buffer.length;
count++;
notify();
}
public synchronized String take() throws InterruptedException {
while (count <= 0) {
wait();
}
String cake = buffer[head];
head = (head + 1) % buffer.length;
count--;
System.out.println(Thread.currentThread().getName() + " takes " + cake);
notify();
return cake;
}
}
public class EaterThread extends Thread {
private final Random random;
private final Table table;
public EaterThread(String name, Table table, long seed) {
super(name);
this.random = new Random(seed);
this.table = table;
}
#Override
public void run() {
try {
while (true) {
String cake = table.take();
Thread.sleep(random.nextInt(1000));
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public class MakerThread extends Thread {
private final Random random;
private final Table table;
private static int id = 0;
public MakerThread(String name, Table table, long seed) {
super(name);
this.random = new Random(seed);
this.table = table;
}
#Override
public void run() {
try {
while (true) {
Thread.sleep(random.nextInt(1000));
String cake = " Cake No." + nextId() + " by " + getName() + " ]";
table.put(cake);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static synchronized int nextId() {
return ++id;
}
}
public class LazyThread extends Thread {
private final Table table;
public LazyThread(String name, Table table) {
super(name);
this.table = table;
}
#Override
public void run() {
while (true) {
try {
synchronized (table) {
table.wait();
}
System.out.println(getName() + " is notified");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
Console output
You need notifyAll instead of notify. Otherwise, the a maker's notify could wake up another maker and put the whole thing into deadlock. Ditto for the lazies.
A better way to do this would be to use one lock for the makers and one lock for the lazies (takers) then you can just use notify when things are added or removed
public synchronized void put(String cake) throws InterruptedException {
while (count >= buffer.length) {
wait();
}
System.out.println(Thread.currentThread().getName() + " puts " + cake);
buffer[tail] = cake;
tail = (tail + 1) % buffer.length;
count++;
notifyAll();
}
public synchronized String take() throws InterruptedException {
while (count <= 0) {
wait();
}
String cake = buffer[head];
head = (head + 1) % buffer.length;
count--;
System.out.println(Thread.currentThread().getName() + " takes " + cake);
notifyAll();
return cake;
}
As the doc says:
public final void notify()
... If any threads are waiting on this object, one of them is chosen
to be awakened. The choice is arbitrary and occurs at the discretion
of the implementation ...
...the awakened thread enjoys no reliable privilege or disadvantage in
being the next thread to lock this object. ...
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify()
You can absolutely implement this so that you notify() only one thread. It depends on when the locked object is released by the preceding thread. If one thread is notified but the resource is still bound to the notifying thread, the released thread goes back to the wait status and after that there is no thread being notified.
When you notifyall() waiting threads and when the first thread does not get the locked object (because still locked by the notifying thread) then the remaining awoken threads will try to catch it.
So, with many awoken threads there is a much higher possibility of the locked object being catched by one of them.

Concurrency issue with threads

I have a simple code, consisting of 4 threads (2 modify the data and 2 read the data). I just wrote this sample code to play around with Semaphor and I am not sure why I get ava.base/java.util.ArrayList$Itr.checkForComodification exception? Here are the source code and thanks for any insights.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static class InnerWriterSemaphoreThread implements Runnable {
private final List<String> fList;
private final Semaphore fWriteSem;
InnerWriterSemaphoreThread(List<String> list, Semaphore w) {
fList = list;
fWriteSem = w;
}
private void prune() {
System.out.println(Thread.currentThread().getName()+" in prune()..");
for (String s : fList) {
fList.remove(s);
}
}
#Override
public void run() {
String name = Thread.currentThread().getName();
String text;
while (true) {
text = RandomTextGenerator.getRandomSNumbertring();
try {
while(!fWriteSem.tryAcquire()){
System.out.println(name+" waiting to accquire semaphore to write..");
Thread.sleep(0L,4);
}
if (fList.size() > 10) {
prune();
}
fList.add(text);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
fWriteSem.release();// notify readers that write has completed
System.out.println(name+" finished writing, releasing semaphore..");
}
}//while()
}//run()
}//WriterSemaphoreThread
public static class InnerReaderSemaphoreThread implements Runnable {
private final List<String> fList;
private final Semaphore fWriteSem;
InnerReaderSemaphoreThread(List<String> list,Semaphore w) {
fList = list;
fWriteSem = w;
}
private void sleep(){
try{
Thread.sleep(0L, 4);
}catch(InterruptedException e){
e.printStackTrace();
}
}
#Override
public void run() {
String name = Thread.currentThread().getName();
while (true) {
System.out.println(name + " in run()..");
try {
while(fList.isEmpty()){
System.out.println(name+" list is empty, going to sleep..");
sleep();
}
while(!fWriteSem.tryAcquire()){
System.out.println(name+" waiting to accquire semaphor to read..");
Thread.sleep(0l,4);
}
for (String text : fList) {
System.out.println(name + " reading from list " + text);
}
}catch (InterruptedException e) {
e.printStackTrace();
}
finally{
fWriteSem.release(); //Notify threads who want to write to the list
System.out.println(name+" finished reading, releasing semaphore and going to sleep..");
sleep();
}
}
}
}//ReaderSemaphoreThread
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Semaphore r = new Semaphore(1);
Thread th1 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 1");
Thread th2 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 2");
Thread th3 = new Thread(new InnerWriterSemaphoreThread(list, r), "Thread 3");
Thread th4 = new Thread(new InnerReaderSemaphoreThread(list, r), "Thread 4");
th2.start();
th4.start();
th1.start();
th3.start();
}
}
Above is the sample source code
As #assylias mentioned in comment it happens when you remove elements from list in foreach loop. Just replace
for (String s : fList) {
fList.remove(s);
}
with
fList.clear();

Monitor in my java program gets into a deadlock

I'm trying to solve single consumer/producer problem using monitor in Java, and the code is as follows. When I run this code, it will finally get stucked. The most typical case is that the consumer calls wait(), and then the producer keeps producing but cannot notify the consumer (although it will call notify()). I don't know why it's happening. Java code:
import java.util.*;
class Monitor {
int length;
int size;
int begin, end;
int queue[];
private static Random randGenerator;
public Monitor() {}
public Monitor(int length) {
this.length = length;
this.size = 0;
begin = end = 0;
queue = new int[length];
randGenerator = new Random(10);
}
public synchronized void produce() throws InterruptedException {
while(size == length) {
System.out.println("Producer waiting");
wait();
}
int produced = randGenerator.nextInt();
size++;
queue[end] = produced;
end = (end + 1) % length;
System.out.println("Produce element " + produced + " size "+size);
// When size is not 1, no thread is blocked and therefore don't need to notify
if(size == 1) {
System.out.println("Notify consumer");
notify();
}
}
public synchronized void consume() throws InterruptedException {
while(size == 0) {
System.out.println("Consumer waiting, size " + size);
wait();
}
size--;
System.out.println("Consume element " + queue[begin] + " size " + size);
begin = (begin + 1) % length;
if(size == length - 1) {
System.out.println("Notify producer");
notify();
}
}
}
class Producer implements Runnable {
Monitor producer;
public Producer(Monitor m) {
producer = m;
}
#Override
public void run() {
producer = new Monitor();
System.out.println("Producer created");
try {
while(true) {
producer.produce();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
Monitor consumer;
public Consumer(Monitor m) {
consumer = m;
}
#Override
public void run() {
System.out.println("Consumer created");
consumer = new Monitor();
try {
while(true) {
consumer.consume();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class monitorTest {
public static void main(String args[]) {
Monitor monitor = new Monitor(10);
Thread t1 = new Thread(new Producer(monitor));
Thread t2 = new Thread(new Consumer(monitor));
t1.start();
t2.start();
}
}
When the control of each thread enters the produce() or consume() methods, the size and length are both zero and hence both threads are waiting for the other to notify. Break this and your code will come out of the deadlock.
public synchronized void produce() throws InterruptedException {
while(size == length) { // size is 0 and length is 0; so wait
System.out.println("Producer waiting");
wait();
}
public synchronized void consume() throws InterruptedException {
while(size == 0) { // size is 0 so wait
System.out.println("Consumer waiting, size " + size);
wait();
}
This is happening because you have a default constructor which you are calling inside the run() method of your Producer and Consumer objects.
class Producer implements Runnable {
Monitor producer;
public Producer(Monitor m) {
producer = m;
}
#Override
public void run() {
producer = new Monitor(); // REMOVE THIS
class Consumer implements Runnable {
Monitor consumer;
public Consumer(Monitor m) {
consumer = m;
}
#Override
public void run() {
System.out.println("Consumer created");
consumer = new Monitor(); // AND REMOVE THIS
Hope this helps!

Multithreaded Web Crawler in Java

I am trying to write a Multithreaded Web Crawler in Java using Jsoup.I have a Java Class "Master" which creates 6 threads(5 for crawling and 1 for maintenance of queues) ,and 3 queues namely "to_do","to_do_next"(to be done in next iteration) and "done"(final links).
I am using sunchronized locks on shared queues.The idea is as soon as all the 5 threads find the "to_do" queue empty they notify a maintenance thread which does some work and notify these threads back.But the problem is the program is getting blocked sometimes (so i assume there is some race condition I am not able to take care of)....also upon checking I found that not all threads are getting notified by maintenace thread.so is it possible that some notify signals might be lost??
Code for Master class
private Queue<String> to_do = new LinkedList<String>();
private Queue<String> done= new LinkedList<String>();
private Queue<String> to_do_next = new LinkedList<String>();
private int level = 1;
private Object lock1 = new Object();
private Object lock2 = new Object();
private Object lock3 = new Object();
private static Thread maintenance;
public static Master mref;
public static Object wait1 = new Object();
public static Object wait2 = new Object();
public static Object wait3 = new Object();
public static int flag = 5;
public static int missedSignals = -1;
public boolean checkToDoEmpty(){
return to_do.isEmpty();
}
public int getLevel() {
return level;
}
public void incLevel() {
this.level++;
}
public static void interrupt() {
maintenance.interrupt();
}
public void transfer() {
to_do = to_do_next;
}
public String accessToDo() {
synchronized(lock1){
String tmp = to_do.peek();
if(tmp != null)
tmp = to_do.remove();
return tmp;
}
}
public void addToDoNext(String url){
synchronized(lock2){
to_do_next.add(url);
}
}
public void addDone(String string) {
synchronized(lock3){
done.add(string);
}
}
public static void main(String[] args){
Master m = new Master();
mref = m;
URL startUrl = null;
try {
startUrl = new URL("http://cse.iitkgp.ac.in");
}catch (MalformedURLException e1) {
e1.printStackTrace();
}
Thread t1 = new Thread(new Worker(1));
Thread t2 = new Thread(new Worker(2));
Thread t3 = new Thread(new Worker(3));
Thread t4 = new Thread(new Worker(4));
Thread t5 = new Thread(new Worker(5));
maintenance = new Thread(new MaintenanceThread());
m.to_do.add(startUrl.toString());
maintenance.start();
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
try {
t1.join();
t2.join();
t3.join();
t4.join();
t5.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*for(String s:m.done)
System.out.println(s);
for(String s:m.to_do)
System.out.println(s);*/
}
Code for Worker threads
public void run() {
while(Master.mref.getLevel() != 3){
if(!Master.mref.checkToDoEmpty()){
String url = Master.mref.accessToDo();
if(url != null && url.contains("iitkgp") && url.contains("http://")){
try {
Document doc = Jsoup.connect(url).get();
org.jsoup.select.Elements links = doc.select("a[href]");
for(org.jsoup.nodes.Element l: links){
Master.mref.addToDoNext(l.attr("abs:href").toString());
}
Master.mref.addDone(url);
} catch (IOException e) {
System.out.println(url);
e.printStackTrace();
}
continue;
}
}
//System.out.println("thread " + id + " about to notify on wait1");
synchronized(Master.wait1){
Master.wait1.notify();
Master.missedSignals++;
}
synchronized(Master.wait2){
try {
Master.wait2.wait();
System.out.println("thread " + id + " coming out of wait2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Terminating " + id + " thread");
Master.flag--;
if(Master.flag == 0)
Master.interrupt();
}
Code for Maintenace thread
while(Master.flag != 0){
try {
synchronized(Master.wait1){
if(Master.missedSignals != -1){
count += Master.missedSignals;
Master.missedSignals = -1;
}
while(count != 5){
Master.wait1.wait();
if(Master.missedSignals != -1)
count += Master.missedSignals;
Master.missedSignals = -1;
count++;
}
count = 0;
}
//System.out.println("in between");
Master.mref.incLevel();
Master.mref.transfer();
synchronized(Master.wait2){
Master.wait2.notifyAll();
}
} catch (InterruptedException e) {
break;
}
}
System.out.println("Mainta thread gone");
Your design is way too complicated
i suggest using for your to_do queue the following: LinkedBlockingQueue
This is a blocking queue, which means that your threads will ask for an object from the queue and only when one will appear they will get the object, till then they will stay blocking.
Just use the following methods to put and take objects in the queue: put() & take()
Please look at the following two links for more explanations on this special queue:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/LinkedBlockingQueue.html
http://tutorials.jenkov.com/java-util-concurrent/linkedblockingqueue.html
Now, your only concern is killing the threads when they are finished with their work, for that I suggest the following:
boolean someThreadStillAlive = true;
while (someThreadStillAlive) {
someThreadStillAlive = false;
Thread.sleep(200);
for (Thread t : fetchAndParseThreads) {
someThreadStillAlive = someThreadStillAlive || t.isAlive();
}
}
This will occur in your main code block, where it will loop & sleep till all threads are finished.
Ohh, instead of take(), you can use poll(int timeout...) where it will wait for the timeout to finish and if no new object is inserted into the queue it will kill the thread.
All of the above, were used successfully in my own crawler.

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