Imitation of Thread Pool doesn't work correctly - java

I've been trying to make a simple implementation of Thread-Pool using Active Objects.
Here is my Main:
public static void main(String[] args){
MyThreadPool tp = new MyThreadPool(100,3);
tp.execute(()->{
try { Thread.sleep(5*1000); } catch (InterruptedException e) {}
System.out.println("42");
});
tp.shutDown();
}
The shutDown method is usually called first through the Main and therefore keeps the Active Objects "alive" unwantedly, but sometimes I get the wanted outcome.
Any idea why there is uncertainty about the result?
Below you can see the rest of the classes:
public class MyThreadPool {
ArrayBlockingQueue<Runnable> q;
ArrayBlockingQueue<ActiveObject> activeObjects;
volatile boolean stop;
AtomicInteger count;
Thread t;
Runnable stopTask;
public MyThreadPool(int capacity, int maxThreads) {
activeObjects = new ArrayBlockingQueue<>(maxThreads);
q = new ArrayBlockingQueue<>(capacity);
count = new AtomicInteger(0);
stopTask = ()->stop = true;
t=new Thread(()->{
//System.out.println("Thread-Pool Started");
while(!stop){
//if queue is empty it is gonna be a blocking call
try {
Runnable task = q.take();
if(task==stopTask)
stopTask.run();
else
//size() is atomic integer
if (count.get() < maxThreads) {
ActiveObject a = new ActiveObject(capacity);
activeObjects.put(a);
count.incrementAndGet();
a.execute(task);
}
//we will assign the next task to the least busy ActiveObject
else {
int minSize = Integer.MAX_VALUE;
ActiveObject choice = null;
for (ActiveObject a : activeObjects) {
if (a.size() < minSize) {
minSize = a.size();
choice = a;
}
}
choice.execute(task);
}
} catch (InterruptedException e) { }
}
//System.out.println("Thread-Pool Ended");
});
t.start();
}
//execute returns right away - just puts into the queue
public void execute(Runnable r ){
// if capacity is full it is gonna be a blocking call
if(!stop)
try { q.put(r); } catch (InterruptedException e) { }
}
public void shutDownNow(){
activeObjects.forEach(a->a.shutDownNow());
stop = true;
t.interrupt();
}
public void shutDown(){
activeObjects.forEach(a->a.shutDown());
execute(stopTask);
}
public class ActiveObject {
ArrayBlockingQueue<Runnable> q;
volatile boolean stop;
Thread t;
public ActiveObject(int capacity) {
q = new ArrayBlockingQueue<>(capacity);
t=new Thread(()->{
//System.out.println("Active Object Started");
while(!stop){
//if queue is empty it is gonna be a blocking call
try {
q.take().run();
} catch (InterruptedException e) { }
}
//System.out.println("Active Object Ended");
});
t.start();
}
//execute returns right away - just puts into the queue
public void execute(Runnable r ){
// if capacity is full it is gonna be a blocking call
if(!stop)
try { q.put(r); } catch (InterruptedException e) { }
}
public void shutDownNow(){
stop = true;
t.interrupt();
}
public void shutDown(){
execute(()->stop=true);
}
public int size(){
return q.size();
}
}

In your main method you create a thread pool (which also creates and starts tp.t thread), enqueue a task into tp.q, and then call tp.shutDown():
MyThreadPool tp = new MyThreadPool(100, 3);
tp.execute(() -> {...});
tp.shutDown();
Imagine that tp.shutDown() in the main thread is executed before the MyThreadPool.t thread processes the enqueued task:
activeObjects.forEach(a -> a.shutDown());
execute(stopTask);
here activeObjects is empty, you enqueue stopTask into tp.q, and main thread finishes.
Now we only have MyThreadPool.t thread, let's see what it does:
while (!stop) {
try {
Runnable task = q.take();
if (task == stopTask)
stopTask.run();
else
if (count.get() < maxThreads) {
ActiveObject a = new ActiveObject(capacity);
activeObjects.put(a);
count.incrementAndGet();
a.execute(task);
}
else {
...
}
} catch (InterruptedException e) {
}
}
At this point q contains 2 tasks: a normal task and stopTask.
In the first loop iteration the normal task is taken from q, and is given for processing to a newly created ActiveObject:
ActiveObject a = new ActiveObject(capacity);
activeObjects.put(a);
count.incrementAndGet();
a.execute(task);
new ActiveObject() also creates and starts its own internal ActiveObject.t thread.
The second loop iteration processes stopTask:
if (task == stopTask)
stopTask.run();
which sets stop = true.
As a result, the next check while (!stop) returns false and MyThreadPool.t thread finishes.
Now we only have ActiveObject.t thread, which hasn't been stopped:
while (!stop) {
try {
q.take().run();
} catch (InterruptedException e) {
}
}
here the thread will keep waiting on q.take() forever.

Related

Ending console based multi threaded program gracefully

I have the following class, I usually run about 10 threads of it
public class MyClass implements Runnable {
private volatile Device device = null;
public MyClass(Device device) {
this.device = device;
}
#Override
public void run() {
while (true) { // <--- I do know that the "true" has to be changed to a Boolean
try {
Worker worker = new Worker();
worker.work();
System.out.println("Waiting 6 seconds!");
Thread.sleep(6 * 1000);
System.out.println("------------------------------------");
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Thread in program ended!");
}
}
and in my main I start the threads like this
for (int i = 0; i < 2; i++) {
(new Thread(new MyClass())).start();
}
This is a console based program. What is the most reliable way to end the program? I think the best way would be to change while (true) to while (Boolean) and somehow change that Boolean for all threads, then when the loop ends, the program will end gracefully.
Here i'm ending it by waiting for a user input but you can change it to fire the stop method from anywhere
public static void main(String[] args) {
List<MyClass> myThreads = new ArrayList<>();
for (int i = 0; i < 2; i++) {
MyClass myClass = new MyClass();
Thread t = new Thread(myClass);
t.start();
myThreads.add(myClass);
}
Scanner in = new Scanner(System.in);
in.next();
for(MyClass t : myThreads){
t.stop();
}
}
class MyClass implements Runnable {
private Boolean flag;
public MyClass() {
this.flag = true;
}
#Override
public void run() {
while (flag) { // <--- I do know that the "true" has to be changed to a Boolean
try {
System.out.println("Waiting 6 seconds!");
Thread.sleep(6 * 1000);
System.out.println("------------------------------------");
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("Thread in program ended!");
}
public void stop(){
this.flag = false;
} }
The easy way would be to store all your threads in a set and make loop joining them at the end.
Be aware that this is not the most ortodox neither the most efficient way to do this.
In your main:
HashSet<Thread> threads = new HashSet();
for (int i = 0; i < 2; i++) {
Thread t = new Thread(new MyClass());
threads.add(t);
t.start();
}
for (Thread thread: threads) {
thread.join();
}
some more material
The following code uses an executor service to fix the number of threads that run at any time, it provides a Future object that also tells you when your thread has shutdown gracefully. They share a shutdown object as well. This offers you a bit more flexibility as the executor service can let you decide how many threads run at any one time gracefully.
First lets created a shared shutdown object that will notify all the threads it is time to shut down. There will be one instance of this and each thread will have a copy.
public static class Shutdown {
private boolean running;
public void shutdown() {
this.running = false;
}
public boolean isRunning() {
return running;
}
}
Next let me just create a dummy thread that does nothing more than sleep forever while it is running. Obviously you can simply replace this with your own thread to do something useful.
public static class MyClass implements Runnable {
final Shutdown shutdown;
public MyClass(Shutdown shutdown) {
this.shutdown = shutdown;
}
#Override
public void run() {
while (shutdown.isRunning()) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
System.out.println("Did not gracefully shut down");
}
}
System.out.println("Thread in program ended!");
}
}
}
Now for the main class which will run everything, this is where the magic happens.
public class Main {
public static void main(String[] args) {
//run exactly 10 threads at a time
ExecutorService executorService = Executors.newFixedThreadPool(10);
//this is how we shut it down
Shutdown globalShutdown = new Shutdown();
//start up the 10 threads
List<Future<?>> futures = new ArrayList<>();
for(int i = 0; i< 10; i++)
futures.add(executorService.submit(new MyClass(globalShutdown)));
//gracefully shut them down
globalShutdown.shutdown();
try {
//wait for them all to shutdown
for(Future<?> future : futures)
future.get();
} catch (InterruptedException e) {
throw new IllegalStateException("This should never happen");
} catch (ExecutionException e) {
throw new IllegalStateException("This should never happen");
}
//everything got shutdown!
}
in practice however you probably also want to handle the case where your thread may not end gracefully due to a bug. Rather than stall forever you might want to add a timeout and if that timeout is exceeded then simply forcibly terminate all remaining threads. To do that replace the above try-catch block with this.
try {
//wait for them all to shutdown
boolean timedout = false;
for(Future<?> future : futures) {
if( !timedout ) {
try {
future.get(30, TimeUnit.SECONDS);
} catch (TimeoutException e) {
timedout = true;
}
}
if(timedout) {
future.cancel(true);
}
}
} catch (InterruptedException | ExecutionException e) {
throw new IllegalStateException("This should never happen");
}

Producer consumer problems without semaphores in java threads synchronization

Hi I have been trying to solve the producer consumer problem in java without semaphores. When I use single producer and single consumer then my code is working fine. But when I add more than one consumer then it is completely messing up, all the consumer threads are going into the synchronized block. I'm not sure why this is happening. Here is my code :
Producer class:
public class Producer implements Runnable {
Object SharedObject = null;
String producerName= null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName=s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out.println("Producer is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName+" Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Consumer Class:
public class Consumer implements Runnable {
Object SharedObject = null;
String consumerName= null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName=s;
}
Consumer c= new Consumer((Main) SharedObject,consumerName);
synchronized void consume(){
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName+" is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName+" consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notifyAll();
System.out.println("Consumer notified the producer to wake up");
}
}
}
public void run() {
while (true) {
c.consume();
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main Class:
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
}
}
You are using notifyAll in the producer, which wakes up all consumer threads waiting on the monitor. If you want only one consumer to wake up, you should use notify From the API documentation:
notify()
Wakes up a single thread that is waiting on this object's monitor.
notifyAll()
Wakes up all threads that are waiting on this object's monitor.
It would also be better for your consumers to actually check that they can consume a resource when they are woken up. If you want to continue to use notifyAll, a consumer should be able to be awoken, and if insufficient resource is available, go back to waiting.
I suggest printing the main.itemCount. This will make it more obvious what the problems you have are.
You have to pay attention to when you are calling notify.
Why does your producer only call notify when there is exactly one item available? Shouldn't the producer call notify whenever there is an item available?
The consumer only tells the producer to wake up when there are 4 items (isn't this full?).
Actually changing notifyAll() to notify() kindoff worked!!! thanks for ua suggestion guys. Here is my code:
Producer class:
package com.source;
import java.util.Random;
public class Producer implements Runnable {
Object SharedObject = null;
String producerName = null;
Random rn = new Random();
public Producer(Main m, String s) {
this.SharedObject = m;
this.producerName = s;
}
public Producer(Main m) {
this.SharedObject = m;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == Main.bufferSize) {
try {
System.out
.println(this.producerName + "is sleeping and waiting for notification form Consumer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount++;
System.out.println(this.producerName + " Produced the item and the item count is : " + Main.itemCount);
if (Main.itemCount == 1) {
SharedObject.notify();
System.out.println("Producer Notified the cosumer to wake up");
}
}
try {
int i = rn.nextInt(100);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Consumer Class:
package com.source;
import java.util.Random;
public class Consumer implements Runnable {
Object SharedObject = null;
String consumerName = null;
Random rn = new Random();
public Consumer(Main m, String s) {
SharedObject = m;
this.consumerName = s;
}
public void run() {
while (true) {
synchronized (SharedObject) {
if (Main.itemCount == 0) {
try {
System.out.println(this.consumerName + " is sleeping and waiting for notify from Producer");
SharedObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Main.itemCount--;
System.out.println(this.consumerName + " consumed 1 item and the item Count is " + Main.itemCount);
if (Main.itemCount == 4) {
SharedObject.notify();
System.out.println("Consumer notified the producer to wake up");
}
}
try {
int i = rn.nextInt(1000);
Thread.sleep(i);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main Class:
package com.source;
public class Main {
static int itemCount = 0;
static int bufferSize = 5;
public static void main(String[] args) {
Main m = new Main();
Thread objP = new Thread(new Producer(m, "Producer1"));
Thread objC = new Thread(new Consumer(m, "Consumer1"));
Thread objC2 = new Thread(new Consumer(m, "Consumer2"));
Thread objC3 = new Thread(new Consumer(m, "Consumer3"));
Thread objP2 = new Thread(new Producer(m, "Producer2"));
Thread objP3 = new Thread(new Producer(m, "Producer3"));
objP.start();
objC.start();
objC2.start();
objC3.start();
objP2.start();
objP3.start();
}
}
Once again thanks to everyone for your valuable time and suggestions.
Sounds like you are past your initial problem but here's some more feedback.
I believe your real problem was not because of notifyAll() but because your buffer tests were if tests instead of while loops. There are classic race conditions where a thread gets awaken but there are no elements in the buffer. See my notes here. So you code should be something like:
while (Main.itemCount == Main.bufferSize) {
and
while (Main.itemCount == 0) {
Calling notifyAll() exacerbated the problem but the race conditions still exist even with just notify(). As you add more consumers or another producer you will see more problems.
Here is some other feedback.
Be very careful of locks within locks. That is a bad pattern typically and one that I use very infrequently. Do you really need consume() to be synchronized?
Object instance names should start with a lowercase letter so it should be sharedObject.
Any object that you are locking on should be private final if at all possible. You wouldn't want it changing to another object.
Using Main. anything is a bad pattern. How about creating an object with the itemCount and bufferSize and then passing the same instance of that object to all of our producer and consumers? It would also be the object you would lock on.
Be careful of sprinkling your thread code with System.out.println(...) messages as others have recommended. System.out is a synchronized class so this will add locks and memory synchronization that may move or fix the problem. Yes. Debugging threaded programs is hard.

how to pause a thread and resume it exactly where it was left off

I'm trying to come with a solution for a thread to pause and resume exactly where it was left off.
So here's a sample code emulating my problem: 2 threads are running in the background: taskThread & busyThread. When busyThread is in system is busy area, taskThread must alt/pause immediately and resume exactly where it was left off. Example, if taskThread was paused at task C (finished) it should resume at D.
I tried to use wait, notify on taskThread but without success.
public class Test
{
private Thread taskThread;
private Thread busyThread;
public static void main(String args[]) throws Exception
{
Test t = new Test();
t.runTaskThread();
t.runBusyThread();
}
public void runTaskThread()
{
taskThread = new Thread(new Runnable(){
#Override
public void run()
{
for (int x=0; x<100; x++)
{
try
{
System.out.println("I'm doing task A for process #"+x);
Thread.sleep(1000);
System.out.println("I'm doing task B for process #"+x);
Thread.sleep(200);
System.out.println("I'm doing task C for process #"+x);
Thread.sleep(300);
System.out.println("I'm doing task D for process #"+x);
Thread.sleep(800);
System.out.println("\n\n");
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}});
taskThread.start();
}
public void runBusyThread()
{
busyThread = new Thread(new Runnable(){
#Override
public void run()
{
while (true)
{
Random rand = new Random();
int randomNum = rand.nextInt(1000);
if (randomNum<400)
{
System.out.println("Wait...system is busy!!!");
try
{ //what should come here to to signal taskThread to paused
Thread.sleep(3000);
//what should come here to to signal taskThread to resume
} catch (InterruptedException e)
{
}
} else
{
try
{
Thread.sleep(300);
} catch (InterruptedException e)
{
}
}
}
}});
busyThread.start();
}
}
There are two very useful classes in concurrency package - CountDownLatch and CyclicBarrier. If you need this behaviour only once, you probably want the first one (as it cannot be reset).
Thread 1 will await until notified by thread 2. Once it was counted down to 0, thread 1 will never block again at await():
CountDownLatch cdl = new CountDownLatch(1);
// thread 1:
cdl.await();
// thread 2:
cdl.countDown();
Threads will block at await() until there are exactly two threads waiting:
CyclicBarrier barrier = new CyclicBarrier(2);
// both threads:
barrier.await();
EDIT:
Here is what I came up with when modifying your code, however it is unclear to me whether it is expected behaviour.
Note a volatile keyword on the CountDownLatch - it is very important here, otherwise taskThread may cache the initial object (new CountDownLatch(0)) and hence never block.
public class Test {
private Thread taskThread;
private Thread busyThread;
private volatile CountDownLatch cdl = new CountDownLatch(0);
public static void main(String args[]) throws Exception {
Test t = new Test();
t.runTaskThread();
t.runBusyThread();
}
public void runTaskThread() {
taskThread = new Thread(() -> {
for (int x = 0; x < 100; x++) {
waitIfSystemBusy();
System.out.println("I'm doing task A for process #" + x);
sleep(1000);
waitIfSystemBusy();
System.out.println("I'm doing task B for process #" + x);
sleep(200);
waitIfSystemBusy();
System.out.println("I'm doing task C for process #" + x);
sleep(300);
waitIfSystemBusy();
System.out.println("I'm doing task D for process #" + x);
sleep(800);
System.out.println("\n\n");
}
});
taskThread.start();
}
public void runBusyThread() {
busyThread = new Thread(() -> {
while (true) {
Random rand = new Random();
int randomNum = rand.nextInt(1000);
if (randomNum < 400) {
System.out.println("Wait...system is busy!!!");
cdl = new CountDownLatch(1); // signal taskThread to pause
sleep(3000);
cdl.countDown(); // signal taskThread to resume
} else {
sleep(300);
}
}
});
busyThread.start();
}
private void waitIfSystemBusy() {
try {
cdl.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
It would be done using the deprecated methods Thread.suspend/resume.
They are deprecated as they are deadlock prone, whereas concurrency mechanisms like locks behave in a designed explicit manner (but still deadlock prone).
I would suggest create a class that implements Runnable which simply keep track of the stages you are in
just as an example (please change accordingly)
class MyRunnable implements Runnable {
private int stage = 0; // if you want it gloabally, then use static
#Override
public void run() {
try{
switch(stage){
case 1:
System.out.println("1");
stage++;
case 2:
System.out.println("2");
Thread.sleep(2000);
stage++;
default:
stage = 0;
}
}catch (Exception e){
}
}
}
now to use such class you just need to create a new thread
for example:
public static void main(String[] args) throws Exception{
MyRunnable myRunnable=new MyRunnable();
new Thread(myRunnable).start(); //it prints 1
Thread.sleep(1000);
new Thread(myRunnable).start(); //prints 2 follow by 2 sec sleep
}
NOTE:
this example wasn't intended to answer the question exactly but rather show a logic how it can be done.
EDIT 1:
what should come here to to signal taskThread to paused
taskThread.interupt();
what should come here to to signal taskThread to resume
taskThread=new Thread(myRunnable);
taskThread.start();
Instead of sleep() I would prefer wait() and notifyAll().
have a Boolean systemBusy, implement get and set methods;
now in thread1
run(){
synchronize(something){
while(isSystemBusy()){
try{
wait();}
catch{}
}
}
}
and on the other thread
run(){
setSystemBusy(true);
//piece of code
//task finished
notifyAll();
setSystemBusy(false);
}
you can use this in multiple waiting threads just remember to set appropriate while condition false after notify all.

How one can pause and/or stop javafx.concurrent.Task?

Say, I've got a javafx.concurrent.Task nested into Thread, ie.:
Task task = new Task();
Thread thread = new Thread(task);
thread.start();
How can I in this situation pause and/or stop executing task nad resume its work?
There is no easy way, except using the deprecated suspend() and resume() methods on the Thread class.
In case you are sure your task doesn't enter synchronized code that would work
Otherwise you would have to have halt points in your task were you check if the Task has been halted and if so call wait() on some object to block the thread. A call to notify on the object would then wake the Thread up and resume. Below is a chunk of pseudo code for that approach.
Note that for this to work as expected you need check the halt variable frequently in the task code.
class MyTask{
volatile boolean halt = false;
Object o = new Object();
public void run(){
while(notDone) {
if (halt) halt();
}
}
private halt(){
synchronized (o){o.wait()}
}
public resume(){
halt = false;
synchronized (o){o.notify()}
}
public suspend(){
halt=true;
}
}
import java.io.IOException;
public class TestThread {
static class PausableRunnable implements Runnable{
volatile boolean shouldHalt = false;
private final Object lock=new Object();
public void run(){
while(true){
if(shouldHalt)halt();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(".");
}
}
private void halt(){
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void pause(){
shouldHalt = true;
}
void resume(){
synchronized (lock){
shouldHalt=false;
lock.notify();
}
}
}
public static void maipn(String[] args) throws IOException {
PausableRunnable pr = new PausableRunnable();
Thread t = new Thread(pr);
t.start();
while(true) {
char c = (char) System.in.read();
if (c == 'p') {
System.out.println("Pausing");
pr.pause();
}
if (c == 'r') {
System.out.println("Resuming");
pr.resume();
}
}
}
}

why is notify not getting called in my java code

Here's my code:
public class ProducerConsumer
{
public static void main(String[] args)
{
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt= new ProducerT(p); // with p obj i am creating thread
ConsumerT ct=new ConsumerT(p); // with same p obj i am creating thread
pt.start();
ct.start(); //i am starting 2 threads
}
}
class ProduceCosumeData
{
boolean flag;
public synchronized void printStringP(int n)
{
for(int i=0;i<n;i++)
{
try{
if(flag) //for frist time flag is flase so, wait will skip
wait();
else
flag=true; //for next time onwards wait() will get call
System.out.print("Pay");
notify();//after this why my wait() not canceling in inprintStringC()
}catch(Exception e)
{
System.out.print(e);
}
}
}
public synchronized void printStringC(int n)
{
for(int i=0;i<n;i++)
{
try{
wait(); // why it is not out of this after notify()
System.out.print("Tm");
notify();
}catch(Exception e)
{
System.out.print(e);
}
}
}
}
class ProducerT extends Thread
{
ProduceCosumeData p;
ProducerT(ProduceCosumeData p)
{
this.p=p; // i am saving the same obj for both threads
}
public void run()
{
p.printStringP(10); //it will print 10 times pay
}
}
class ConsumerT extends Thread
{
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p)
{
this.p=p; // i am saving the same obj for both threads
}
public void run()
{
p.printStringC(10); //it will print 10 times tm
}
}
I am expecting the following output:
PayTm
PayTm
PayTm
... 10 times
but what I'm getting output is this:
Pay..
This is followed by a long wait.
The above two functions are in same object.
Why is the notify not releasing the wait() function? Even when I use notifyAll(), the output remains the same.
In you code, one of your threads is calling notify and the other is still not waiting. This produces a deadlock with both threads waiting.
You need to fix your use of the synchronization flag, don't call wait if it is not needed. Also, checking the locking condition is still available after the wait() is a good practice.
This is your ProduceConsumeData class with the use of the flag fixed:
class ProduceCosumeData
{
boolean flag;
public synchronized void printStringP(int n)
{
for(int i=0;i<n;i++)
{
try{
while (flag == true) {
wait();
}
flag=true;
System.out.print("Pay");
notify();
}catch(Exception e)
{
System.out.print(e);
}
}
}
public synchronized void printStringC(int n)
{
for(int i=0;i<n;i++)
{
try{
while(flag == false) {
wait();
}
System.out.print("Tm");
flag = false;
notify();
}catch(Exception e)
{
System.out.print(e);
}
}
}
}
You have used a general wait() with the synchronization in the method. Try using an object-synchronised version, such as synchronized(this){ wait(); } then whatever, to prevent cyclic dependencies of multiple threads on the same object, which is very very dangerous for any multithreaded program.
Or, more simply, implement a proper clone() method in your ProducerConsumerData class, and then to the 1st thread pass this object, and to the next pass its clone. Try using p.clone() instead of p in the second thread's constructor.
As answered above, you can make printStringP() 's notify() only get called when flag is true, not always.
This is the classic misconception that trips up almost everyone who tries to use wait and notify. Really they are so old and broken they shouldn't even be taught any more IMHO.
When printStringP calls notify() printStringC is not waiting yet.
class ProduceCosumeData {
// Variable shared between threads should be volatile.
volatile boolean flag;
public synchronized void printStringP(int n) {
for (int i = 0; i < n; i++) {
try {
//for frist time flag is flase so, wait will skip
if (flag) {
System.err.println("Waiting in printStringP");
wait();
} else {
System.err.println("flag now true");
flag = true; //for next time onwards wait() will get call
}
System.out.print("Pay");
System.err.println("printStringP notify");
notify();//after this why my wait() not canceling in inprintStringC()
} catch (Exception e) {
System.out.print(e);
}
}
}
public synchronized void printStringC(int n) {
for (int i = 0; i < n; i++) {
try {
System.err.println("Waiting in printStringC");
wait(); // why it is not out of this after notify()
System.out.print("Tm");
System.err.println("printStringC notify");
notify();
} catch (Exception e) {
System.out.print(e);
}
}
}
}
class ProducerT extends Thread {
ProduceCosumeData p;
ProducerT(ProduceCosumeData p) {
this.p = p; // i am saving the same obj for both threads
}
public void run() {
p.printStringP(10); //it will print 10 times pay
}
}
class ConsumerT extends Thread {
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p) {
this.p = p; // i am saving the same obj for both threads
}
public void run() {
p.printStringC(10); //it will print 10 times tm
}
}
public void test() {
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt = new ProducerT(p); // with p obj i am creating thread
ConsumerT ct = new ConsumerT(p); // with same p obj i am creating thread
pt.start();
ct.start(); //i am starting 2 threads
}
prints
flag now true
PayprintStringP notify
Waiting in printStringP
Waiting in printStringC
To fix this don't use wait/notify it is broken for all but the very experienced. The same functionality can be achieved in a stable fashion using Locks and Conditions or almost any other java.util.concurrent class.
In the second iteration of printStringP the attribute flag is true and then the two threads are waiting.
Please find the below code snippet.
package com.java.examples;
public class ProducerConsumer {
public static void main(String[] args) throws InterruptedException {
ProduceCosumeData p = new ProduceCosumeData();
ProducerT pt = new ProducerT(p); // with p obj i am creating thread
ConsumerT ct = new ConsumerT(p); // with same p obj i am creating thread
pt.start();
Thread.sleep(1000);
ct.start(); // i am starting 2 threads
}
}
class ProduceCosumeData {
boolean flag = false;
public synchronized void printStringP(int n) {
for (int i = 0; i < n; i++) {
try {
if (flag) {
notify();
} else
flag = true;
System.out.println("Pay");
if (i <= n - 1) {
wait();
} else {
break;
}
} catch (Exception e) {
System.out.print(e);
}
}
notify();
}
public synchronized void printStringC(int n) {
for (int i = 0; i < n; i++) {
try {
if (flag) {
System.out.println("Tm");
if (i <= n - 1) {
notify();
} else {
break;
}
} else
flag = false;
wait();
} catch (Exception e) {
System.out.print(e);
}
}
}
}
class ProducerT extends Thread {
ProduceCosumeData p;
ProducerT(ProduceCosumeData p) {
this.p = p; // i am saving the same obj for both threads
}
public void run() {
p.printStringP(10); // it will print 10 times pay
}
}
class ConsumerT extends Thread {
ProduceCosumeData p;
ConsumerT(ProduceCosumeData p) {
this.p = p; // i am saving the same obj for both threads
}
public void run() {
p.printStringC(10); // it will print 10 times tm
}
}

Categories

Resources