how to properly implement producer - consumer in Java - java

I implemented producer consumer like this.
But it is throwing error.
I tried to use this method of using lock. Link
class Testclass {
Boolean isFresh = false;
int count = 0;
public synchronized void GET(String threadName){
while(!isFresh){
try {
isFresh.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("GET method was called : " + count + " " + threadName);
isFresh = false;
isFresh.notify();
}
public synchronized void PUT(String threadName){
while(isFresh){
try{
isFresh.wait();
}catch( InterruptedException e){
e.printStackTrace();
}
}
count++;
System.out.println("PUT method was called : " + count + " " + threadName);
isFresh = true;
isFresh.notify();
}
}
class Producer implements Runnable{
Testclass q;
String name;
Producer(Testclass q, String name){
this.q = q;
this.name = name;
}
public void run(){
while(true){
int time = (int)(Math.random() * 10000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
q.PUT(this.name);
}
}
}
class Consumer implements Runnable{
Testclass q;
String name ;
Consumer(Testclass q,String name){
this.q = q;
this.name = name;
}
public void run(){
while(true){
int time = (int)(Math.random() * 10000);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
q.GET(this.name);
}
}
}
public class Main {
public static void main(String[] args){
Testclass t = new Testclass();
Thread t1 = new Thread(new Consumer(t, "consumer 1"));
Thread t2 = new Thread(new Consumer(t, "consumer 2"));
Thread t3 = new Thread(new Producer(t, "producer 1"));
Thread t4 = new Thread(new Producer(t, "producer 2"));
t1.start();
t2.start();
t3.start();
t4.start();
try{
t1.join();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
this implementation throws following error.
Please explain
why all the threads are throwing Illegal MonitorStateException?
PUT method was called : 1 producer 1
Exception in thread "Thread-2" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.notify(Native Method)
at Testclass.PUT(Main.java:34)
at Producer.run(Main.java:54)
at java.base/java.lang.Thread.run(Thread.java:832)
GET method was called : 1 consumer 1
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.notify(Native Method)
at Testclass.GET(Main.java:19)
at Consumer.run(Main.java:76)
at java.base/java.lang.Thread.run(Thread.java:832)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:321)
at Testclass.GET(Main.java:12)
at Consumer.run(Main.java:76)
at java.base/java.lang.Thread.run(Thread.java:832)
PUT method was called : 2 producer 2
Exception in thread "Thread-3" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.notify(Native Method)
at Testclass.PUT(Main.java:34)
at Producer.run(Main.java:54)
at java.base/java.lang.Thread.run(Thread.java:832)
Process finished with exit code 0
I want to know why is the output like that?
and what is the correct way of implementing it?

You should use a BlockingQueue. Then you don't have to use wait/notify or even synchronzied.
class Testclass {
BlockingQueue<Integer> queue = new ArrayBlockingQueue(1);
AtomicInteger count = new AtomicInteger(0);
public void GET(String threadName) throws InterruptedException{
Integer i = queue.take();
count.getAndIncrement();
System.out.println("GET method was called : " + count + " " + threadName);
}
public void PUT(String threadName) throws InterruptedException{
int c = count.get();
queue.put(c);
count.getAndIncrement();
System.out.println("PUT method was called : " + count + " " + threadName);
}
}
I'm not sure what you want to do with count. This is readily extensible by changing the size of your Queue.

Related

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();

Understanding multi threading wait and notify [duplicate]

This question already has answers here:
How to use wait and notify in Java without IllegalMonitorStateException?
(12 answers)
Closed 5 years ago.
I am learning multi threading and I am trying to understand how to use wait and notify methods of Object class. I have gone through this link https://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example and have written the following program
Waiter
public class Waiter implements Runnable {
private Message m;
public Waiter(Message m) {
this.m = m;
}
public void run() {
String name = Thread.currentThread().getName();
System.out.println(t1 + " thread waiting for message");
synchronized (m) {
try {
m.wait();
System.out.println(t1 + " " + m.getText());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(t1 + " thread waiting for message");
}
}
Notifier
public class Notifier implements Runnable {
private Message m;
public Notifier(Message m) {
this.m = m;
}
public void run() {
synchronized (m) {
try {
Thread.sleep(2000);
m.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Test
public class WaitNotifyTest {
public static void main(String[] str) {
Message m = new Message("hello");
new Thread(new Waiter(m), "t1").start();
new Thread(new Waiter(m), "t2").start();
new Thread(new Notifier(m)).start();
}
}
When I execute the program, it sometimes terminates properly, sometimes it waits indefinitely, sometimes one of the thread terminates and the other waits indefinitely. Can anyone please tell me what is wrong here?
Also I want to know few examples of real time applications of wait and notify methods.
when you are doing wait best practice is do in a while loop with a condition.There can be scenario where thread will notify and after that other thread enter wait state.So thread will go always in wait state
Modified code:
public class Waiter implements Runnable {
private Message m;
public Waiter(Message m) {
this.m = m;
}
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name + " thread waiting for message");
synchronized (m) {
try {
while (m.getText() == null) {
m.wait();
}
System.out.println(name + " " + m.getText());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(name + " thread waiting for message");
}
}
public class Notifier implements Runnable {
private Message m;
public Notifier(Message m) {
this.m = m;
}
public void run() {
synchronized (m) {
m.setText("hello");
m.notifyAll();
}
}
}
public class WaitNotifyTest {
public static void main(String[] str) {
Message m = new Message();
new Thread(new Waiter(m), "t1").start();
new Thread(new Waiter(m), "t2").start();
new Thread(new Notifier(m)).start();
}
}

How to notify certain thread in java

In below code My application run may thread. But How to I notify certain thread.
My task is print all the thread from Server object msg String when String msg change.
class Server{
static String msg;
synchronized void setMsg(String msg){
this.msg = msg ;
notifyAll();
}
synchronized void proccess(){
while(true){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" : "+Server.msg);
}
}
}
Here is my thread class :
class MyThread extends Thread {
Server ser ;
public MyThread(Server ser) {
this.ser = ser ;
this.start();
}
public void run() {
ser.proccess();
}
}
Main Meth() :
class Thread_test {
static String[] name = null ;
public static void main(String[] args) throws InterruptedException {
Server ser = new Server();
for (int i = 0 ; i < 5 ; i++){
MyThread t1 = new MyThread(ser);
t1.setName("Thread "+i);
}
while(true){
Thread.sleep(5000);
ser.sendMsg("Msg : current time is = " + System.currentTimeMillis());
}
}
I change the Server message string once every 5 sec. When change the message I call notifyAll(). This notifyall is wakeup all the waiting thread. But what I want is i.e : I create 10 thread and setName Thread_1 Thread_2 ..etc., Now I want to notify some thread like Thread_1, Thread_4 and Thread_9. I try below func
while(true){
Thread.sleep(5000);
ser.sendMsg("Msg : current time is = " + System.currentTimeMillis());
for ( Thread t : Thread.getAllStackTraces().keySet() ){
if(t.getName().equals("Thread_1") || t.getName().equals("Thread_4") || t.getName().equals("Thread_9")){
t.notify();
}
}
}
I got Exception in thread "main" java.lang.IllegalMonitorStateException
Thank you in advance for any help you can provide.
class Server{
String msg;
void sendMsg(String msg){
this.msg = msg ;
}
public void proccess() throws InterruptedException{
while(true){
synchronized (Thread.currentThread()) {
Thread.currentThread().wait();
}
System.out.println(Thread.currentThread().getName()+" : "+this.msg);
}
}
}
Remove the class object wait() and add Thread.wait() and add
synchronized(t){
t.notify();
}
I don't know it is a correct war or Not. If it wrong provide efficient way.

Why the same thread trying to lock the resource?

The main class trying to create 4 threads
After running the threads, each thread tries to lock. And when one thread gets the lock, the rest will wait to unlock.
In my case, once Thread 0 found that the resource is locked, and then Thread 0 went in the wait state, then why again Thread 0 tries to lock the resource.
package com.test.thread;
public class LockImplementation {
public static void main(String[] args) {
MyNewThread myThread1 = new MyNewThread(1);
MyNewThread myThread2 = new MyNewThread(2);
MyNewThread myThread3 = new MyNewThread(3);
MyNewThread myThread4 = new MyNewThread(3);
myThread1.start();
myThread2.start();
myThread3.start();
myThread4.start();
}
}
class Lock {
private boolean isLocked = false;
private Thread lockingThread = null;
int count = 0;
public synchronized void lock() throws InterruptedException {
if (isLocked) {
System.out.println("trying to lock by thread " +
lockingThread.getName());
wait();
}
System.out.println("Locked by thread " +
Thread.currentThread().getName());
isLocked = true;
lockingThread = Thread.currentThread();
}
public synchronized void unLock() {
if (this.lockingThread != Thread.currentThread()) {
throw new IllegalMonitorStateException("Calling thread has not locked this lock");
}
isLocked = false;
lockingThread = null;
notify();
}
}
class MyNewThread extends Thread {
int thNo;
private static Lock lock;
public MyNewThread(int thNo) {
Thread.currentThread().setName(thNo + "");
this.thNo = thNo;
lock = new Lock();
}
#Override
public void run() {
System.out.println("start running thread no " +
Thread.currentThread().getName());
try {
lock.lock();
Thread.sleep(10000);
lock.unLock();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end running thread no " +
Thread.currentThread().getName());
}
}
Why is the same thread trying to lock the resource?
This happens because when first time you enter lock method you set your locking thread as first that enters it. Next threads when call lock() see that isLocked is true and wait, but locking thread still the same and it doesn't update.

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.

Categories