Replace Await, Signal, SignalAll with wait,notify and notifyAll - java

I want to replace await(),signalAll() with wait(),notifyAll() (java's default monitor) and my code listed below, the problem is that once thread get into waiting state. it never be notified again.. Thanks for your help.
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AccountThreadCommunicationDefault {
private static Account account = new Account();
private static Random random = new Random();
public static void main(String... args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.execute(new WithdrawTask());
es.execute(new DepositTask());
es.shutdown();
}
private static class WithdrawTask implements Runnable {
public void run() {
while (true) {
account.withdraw(random.nextInt(600));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private static class DepositTask implements Runnable {
public void run() {
while (true) {
account.deposit(random.nextInt(500));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
private static class Account {
private Integer balance = 500;
private static Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// private Object object = new Object();
// public synchronized void deposit(int count) {
public void deposit(int count) {
try {
lock.lock();
System.out.print("当前账户余额:" + balance);
balance += count;
System.out.println(" 存款:" + count + " 账户余额(deposit): "
+ getBalance());
// synchronized (object) {
// object.notifyAll();
// }
synchronized (this) {
this.notify();
}
} catch (IllegalMonitorStateException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void withdraw(int count) {
try {
lock.lock();
while (balance < count) {
System.out.println("余额不足:" + getBalance() + " 等待存款..");
// synchronized (object) {
// object.wait();
// }
synchronized (this) {
this.wait();
}
System.out.print("当前账户余额:" + balance);
balance -= count;
System.out.println(" 取现:" + count + " 账户余额(withdraw): "
+ getBalance());
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public int getBalance() {
return this.balance;
}
}
}

You have a deadlock. The Withdraw task is waiting on the Account object's monitor, while holding the ReentrantLock locked. The Deposit task can not notify() the Account object monitor because it can't lock the ReentrantLock.
You need to wait() and notify() the same object that you are using as a mutex. Doesn't matter whether it's the ReentrantLock or the Account object's monitor. But it won't work the way you wrote it with two different locks.

Related

java.lang.IllegalMonitorStateException being thrown from methods running in threads

I am trying to create basic producer/consuner class using:
public class ProducerConsumer {
private final static int MAX_SIZE = 100;
private Queue<String> data = new PriorityQueue<>();
private Lock lock = new ReentrantLock();
private Condition bufferFull = lock.newCondition();
private Condition bufferEmpty = lock.newCondition();
public void produce(){
while(true) {
try {
lock.lock();
while (data.size() >= MAX_SIZE) {
bufferFull.await();
}
addData();
bufferEmpty.notifyAll();
} catch (InterruptedException e) {
System.out.println("error produce");
} finally {
lock.unlock();
}
}
}
public void consume(){
while(true) {
try {
lock.lock();
while (data.isEmpty()) {
bufferEmpty.await();
}
String value = data.poll();
System.out.println("Thread " + Thread.currentThread().getName() + " processing value " + value);
bufferFull.notifyAll();
} catch (InterruptedException e) {
System.out.println("error consume");
} finally {
lock.unlock();
}
}
}
private void addData(){
IntStream.range(0,10).forEach( i ->
data.add(new Date().toString())
);
}
public void start(int consumerNumber){
IntStream.range(0,consumerNumber)
.mapToObj(i -> new Thread(this::consume))
.collect(Collectors.toList())
.forEach(Thread::start);
Thread t = new Thread(this::produce);
t.start();
}
}
However it keeps throwing error: java.lang.IllegalMonitorStateException. My question is, why does it throw this error? method of this intance are running in threads, so they should own condition lock thus i dont understand meaning behind this error.
Thanks for help!
bufferEmpty.notifyAll() is the wrong method to call. That method requires you hold the monitor on the "bufferEmpty" object itself, which is unrelated to the lock instance you're using.
The right method to call is
bufferEmpty.signalAll();

lock in java multithreading is not working

//I have this main class
package IntroductionLocks;
public class Intro {
public static void main(String[] args) {
NoLockATM noLockATM = new NoLockATM();
LockedATM lockedATM = new LockedATM();
MyClass thread1 = new MyClass(noLockATM, lockedATM);
MyClass thread2 = new MyClass(noLockATM, lockedATM);
thread1.start();
thread2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
thread1.waitUntilDone();
thread2.waitUntilDone();
System.out.println("NoLock ATM: " + noLockATM.getBalance());
System.out.println("Locked ATM: " + lockedATM.getBalance());
int v = thread1.delta + thread2.delta + 100;
System.out.println("Should Be: " + v);
System.out.println("Program terminating.");
}
}
//// 2nd class
package IntroductionLocks;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import CtCILibrary.AssortedMethods;
public class MyClass extends Thread {
private NoLockATM noLockATM;
private LockedATM lockedATM;
public int delta = 0;
private Lock completionLock;
public MyClass(NoLockATM atm1, LockedATM atm2) {
noLockATM = atm1;
lockedATM = atm2;
completionLock = new ReentrantLock();
}
public void run() {
//question here
completionLock.lock();
int[] operations = {10,20};//AssortedMethods.randomArray(20, -50, 50);
for (int op : operations) {
System.out.println(Thread.currentThread().getName());
delta += op;
if (op < 0) {
int val = op * -1;
noLockATM.withdraw(val);
lockedATM.withdraw(val);
} else {
noLockATM.deposit(op);
lockedATM.deposit(op);
}
}
completionLock.unlock();
}
public void waitUntilDone() {
completionLock.lock();
completionLock.unlock();
}
}
//// 3rd class LockedATM
package IntroductionLocks;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockedATM {
private Lock lock;
private int balance = 100;
public LockedATM() {
lock = new ReentrantLock();
}
public int withdraw(int value) {
lock.lock();
int temp = balance;
try {
Thread.sleep(100);
temp = temp - value;
Thread.sleep(100);
balance = temp;
} catch (InterruptedException e) { }
lock.unlock();
return temp;
}
public int deposit(int value) {
lock.lock();
int temp = balance;
try {
Thread.sleep(100);
temp = temp + value;
Thread.sleep(100);
balance = temp;
} catch (InterruptedException e) { }
lock.unlock();
return temp;
}
public int getBalance() {
return balance;
}
}
my question is...why completionLock.lock() in run method is not locking the resource. When i run the program, in System.out.println(Thread.currentThread().getName())
i get below output:
Thread-1
Thread-0
Thread-0
Thread-1
NoLock ATM: 130
Locked ATM: 160
Should Be: 160
Program terminating.
`enter code here`isnt lock supposed to lock the resource....that mean only one thread can get access to it at a time.....????? then why it is showing that first thread 1 is getting acces then thread 0 then again thread 0 and then thread1 ???
Isnt only thread1/0 should get first completed than other??
Also what is wait until done is supposed to do???
Each of your runnables has it's own lock object. That is the answer.
You need to have a shared lock. Or use one of your ATM objects as lock
The problem is with the usage of the Reentrant lock. In your case, each instance of MyClass thread will have its own instance of the completionLock. For you to synchronize the 2 instances of MyClass thread you should be using a shared object. Create the completionLock instance in the main method and pass the instance to both the threads
new MyClass(noLockATM, lockedATM, completionLock);
public MyClass(NoLockATM atm1, LockedATM atm2, ReentrantLock completionLockArg) {
this.noLockATM = atm1;
this.lockedATM = atm2;
this.completionLock = completionLockArg;
}

Lock and Condition about thread communication in java

I'm a java beginner and I write below code while learning Thread in java. I think, if I lock in Resource.set() and comment out the Lock.unlock(), the code in Resource.out() can't be executed because I can't unlock in when I want to execute out method. BTW, whether I comment out the unlock in the set() or in out(), the program will execute in this way:
Thread[Thread-1,5,main]....Produce....chicken1
Thread[Thread-2,5,main]....Consume..........chicken1
Thread[Thread-0,5,main]....Produce....chicken2
Thread[Thread-3,5,main]....Consume..........chicken2 ......
I think a long time and don't understand about it. I just learned it, maybe I have a wrong understanding,so I hope someone's help.
Please forgive my poor English. Thank you very much. My code is here:
package Thread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadStudying {
public static void main(String[] args) {
Resource r = new Resource();
Thread t0 = new Thread(new Producer(r));
Thread t1 = new Thread(new Producer(r));
Thread t2 = new Thread(new Consumer(r));
Thread t3 = new Thread(new Consumer(r));
t0.start();
t1.start();
t2.start();
t3.start();
}
static class Resource {
private String name;
private int count = 1;
boolean isOut = false;
Lock lock = new ReentrantLock();
Condition pro_con = lock.newCondition();
Condition consu_con = lock.newCondition();
public void set(String name) {
lock.lock();
try {
while (isOut) {
try {
pro_con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + count;
System.out.println(Thread.currentThread() + "....Produce...." + this.name);
count++;
isOut = true;
consu_con.signal();
}
finally {
lock.unlock();
}
}
public void out() {
lock.lock();
try {
while (!isOut) {
try {
consu_con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + "....Consume.........." + this.name);
isOut = false;
pro_con.signal();
}
finally {
//lock.unlock();
}
}
}
static class Producer implements Runnable {
Resource r;
Producer(Resource r) {
this.r = r;
}
public void run() {
while (true) {
r.set("chicken");
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
Resource r;
Consumer(Resource r) {
this.r = r;
}
#Override
public void run() {
while (true) {
r.out();
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
In both producer and consumer, you are calling lock.await repeatly by
while (true) {
//
}
From the doc, when you call lock.await :
The lock associated with this Condition is atomically released
So, whether you comment out lock.unlock or not, both producer and consumer will not be blocked.
P.S. Use below code to log more details about getting and releasing lock:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadStudying {
public static void main(String[] args) {
Resource r = new Resource();
Thread t0 = new Thread(new Producer(r), "Producer 1");
Thread t1 = new Thread(new Producer(r), "Producer 2");
Thread t2 = new Thread(new Consumer(r), "Consumer 1");
Thread t3 = new Thread(new Consumer(r), "Consumer 2");
t0.start();
t1.start();
t2.start();
t3.start();
}
static class Resource {
private String name;
private int count = 1;
boolean isOut = false;
Lock lock = new ReentrantLock();
Condition pro_con = lock.newCondition();
Condition consu_con = lock.newCondition();
public void set(String name) {
System.out.println(Thread.currentThread() + "before lock");
lock.lock();
System.out.println(Thread.currentThread() + "get lock");
try {
while (isOut) {
try {
System.out.println(Thread.currentThread() + "release lock");
pro_con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name + count;
System.out.println(Thread.currentThread() + "....Produce...." + this.name);
count++;
isOut = true;
consu_con.signal();
}
finally {
}
}
public void out() {
System.out.println(Thread.currentThread() + "before lock");
lock.lock();
System.out.println(Thread.currentThread() + "get lock");
try {
while (!isOut) {
try {
System.out.println(Thread.currentThread() + "release lock");
consu_con.await();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + "....Consume.........." + this.name);
isOut = false;
pro_con.signal();
}
finally {
//lock.unlock();
}
}
}
static class Producer implements Runnable {
Resource r;
Producer(Resource r) {
this.r = r;
}
public void run() {
while (true) {
r.set("chicken");
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
static class Consumer implements Runnable {
Resource r;
Consumer(Resource r) {
this.r = r;
}
#Override
public void run() {
while (true) {
r.out();
try {
Thread.sleep(500);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
FirstOfAll, "if I lock in Resource.set() and comment out the Lock.unlock(), the code in Resource.out() can't be executed ". This statement of yours is wrong.
Let me clarify why,
In your posted code, where out() has no unlock. I assume you have no problem that one of the Consumer threads (t2 or t3) have no problem in acquiring the lock.
So lets say t2 acquired the lock, while entering out() method and didn't release the lock while exiting out() method. But you overlooked the fact that out() method is executed in infinite loop inside run() method of Consumer Runnable. So when t2 exits out(), sleep of 500 milliseconds; its still in possession of the lock. When it enters the out() method in its next iteration, it executes Lock.lock() on the same lock it already has. Since the lock is Reentrant Lock, it proceeds and executes await() where it releases the lock; and the other threads(Producer threads) waiting on the lock gets chance to acquire the lock.

java wait and notify

I'm taking one Integer variable and sharing with two threads. One thread should print even numbers and one thread should print odd number sequentially.
But notify() throwing IllegalMonitorStateException.
package mywaitnotifytest;
public class App {
public static void main(String[] args) {
Integer i=0;
Even even = new Even(i);
even.setName("EvenThread");
Odd odd = new Odd(i);
odd.setName("OddThread");
even.start();
odd.start();
}
}
class Even extends Thread{
Integer var;
Even(Integer var){
this.var=var;
}
#Override
public void run() {
while(true){
synchronized (var) {
if(var%2==0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
class Odd extends Thread{
Integer var;
Odd(Integer var){
this.var=var;
}
#Override
public void run() {
while(true){
synchronized (var) {
if(var%2!=0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
And the output is :
OddThread 1
Exception in thread "OddThread" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at mywaitnotifytest.Odd.run(App.java:67)
I think this is sufficiently different to the usual answer to give another one.
In this case you are using synchronized. When you apply a lock it is on a object not a reference.
synchronized (var) {
This locks the object var references, not on var as a field.
var++;
This replaces the object var points to. It is the same as
var = Integer.valueOf(var.intValue() + 1);
Note: Integer and indeed all the primitive wrappers are Immutable. When you perform any operation on them you are actually unboxing, calculating using the primitive value and re-boxing the object. It is possible to get the same object back if it is pooled. e.g.
Integer i = 10;
i += 0; // gives back the same object.
However, if the object is not pooled
Double d = 10;
d += 0; // creates a new object.
var.notify();
Attempts the call notify on the new object, not the one which was locked.
You shouldn't attempt to lock a field which you mutate. It won't do what it appears to do. You also shouldn't lock on a pooled object. In this case you could have another thread using the same Integer for an unrelated purpose and notify() will wake up an unrelated thread.
To use wait/notify correctly, you should
notify() or notifyAll() after a state change in another shared field.
you should use a while loop for wait() to check the state change.
If you don't do this
notify can be lost if another thread is not waiting.
wait can wake spuriously, even when no notify was called.
For the above requirement what is the edit suggested in the code? How do i share the same object for multiple threads?
public class PingPong implements Runnable {
static class Shared { int num; }
private final Shared var;
private final int bit;
public static void main(String[] args) {
Shared var = new Shared();
new Thread(new PingPong(var, 0), "EvenThread").start();
new Thread(new PingPong(var, 1), "OddThread").start();
}
PingPong(Shared var, int bit) {
this.var = var;
this.bit = bit;
}
#Override
public void run() {
try {
String name = Thread.currentThread().getName();
while (true) {
synchronized (var) {
while (var.num % 2 == bit)
var.wait();
var.num++;
System.out.println(name + " " + var.num);
var.notify();
}
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
Instead of using Integer wrapper class,I created my own class and now It works fine.
package mywaitnotifytest;
public class App {
public static void main(String[] args) {
MyInt i = new MyInt(0);
Even even = new Even(i);
even.setName("EvenThread");
Odd odd = new Odd(i);
odd.setName("OddThread");
even.start();
odd.start();
}
}
class Even extends Thread {
MyInt var;
Even(MyInt var) {
this.var = var;
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (var) {
if (var.i % 2 == 0) {
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var.i++;
System.out.println(Thread.currentThread().getName() + " " + var.i);
var.notify();
}
}
}
}
class Odd extends Thread {
MyInt var;
Odd(MyInt var) {
this.var = var;
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (var) {
if (var.i % 2 != 0) {
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var.i++;
System.out.println(Thread.currentThread().getName() + " " + var.i);
var.notify();
}
}
}
}
class MyInt {
int i = 0;
public MyInt(int i) {
super();
this.i = i;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "" + i;
}
}

Java thread program not working using wait() and notifyAll()

Below is my program. Always the thread 0 gets the printer, other threads do not get it.
There is one printer object, and i want multiple job threads to use the printer. How to make this program work so that all jobs get the printer. For me the code flow seems to be fine. Am synchronizing on a single printer object. Please help.
package classesTesting;
public class PrinterQueue {
final static Printer printer = new Printer();;
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("In Main");
for (int i = 0; i < 5; i++) {
new Thread(new Jobs(), "Thread - " + i).start();
System.out.println("started " + i + " thread");
}
}
}
class Printer {
private boolean isUsed;
Printer() {
this.isUsed = false;
}
public void setUsed(boolean used) {
this.isUsed = used;
}
public boolean isUsed() {
return this.isUsed;
}
}
class Jobs implements Runnable {
String name;
boolean isDataAvailble;
Jobs() {
this.isDataAvailble = true;
}
public void setNoData(boolean noData) {
this.isDataAvailble = false;
}
#Override
public void run() {
while (isDataAvailble) {
if (PrinterQueue.printer.isUsed()) {
try {
System.out.println(Thread.currentThread()
+ "WAITING FOR PRINTER");
synchronized (PrinterQueue.printer) {
PrinterQueue.printer.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
synchronized (PrinterQueue.printer) {
System.out.println(Thread.currentThread() + "GOT PRINTER");
PrinterQueue.printer.setUsed(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrinterQueue.printer.setUsed(false);
PrinterQueue.printer.notify();
}
}
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Hi, I have revised my program for getting lock first then condition checking. Even then the thread 0 always gets the printer. Other threads starve.
Revised program:
package classesTesting;
public class PrinterQueue {
static Printer printer;
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("In Main");
printer = new Printer();
for (int i = 0; i < 5; i++) {
Jobs j1 = new Jobs();
j1.setPrinter(printer);
Thread t1 = new Thread(j1, "Thread - " + i);
t1.start();
System.out.println("started " + i + " thread");
}
}
}
class Printer {
private boolean isUsed;
Printer() {
this.isUsed = false;
}
public void setUsed(boolean used) {
this.isUsed = used;
}
public boolean isUsed() {
return this.isUsed;
}
}
class Jobs implements Runnable {
String name;
Printer printer;
public Printer getPrinter() {
return printer;
}
public void setPrinter(Printer printer) {
this.printer = printer;
}
boolean isDataAvailble;
Jobs() {
this.isDataAvailble = true;
}
public void setNoData(boolean noData) {
this.isDataAvailble = false;
}
#Override
public void run() {
while (isDataAvailble) {
synchronized (PrinterQueue.printer) {
if (this.printer.isUsed()) {
try {
System.out.println(Thread.currentThread()
+ "WAITING FOR PRINTER");
PrinterQueue.printer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
System.out.println(Thread.currentThread() + "GOT PRINTER");
PrinterQueue.printer.setUsed(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrinterQueue.printer.setUsed(false);
PrinterQueue.printer.notify();
}
}
}
}
}
If you want the resource to be available for all the threads in fair manner, it's much better to use ReentrantLock with fair = true parameter. Also never rely on non-volatile variables changed in concurrent way. Here's the fixed code:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrinterQueue {
static Printer printer;
public static void main(String[] args) {
System.out.println("In Main");
printer = new Printer();
for (int i = 0; i < 5; i++) {
// I added printer constructor parameter to pass the same printer
// to all the Jobs
new Thread(new Jobs(printer), "Thread - " + i).start();
System.out.println("started " + i + " thread");
}
}
}
class Printer {
// internally printer holds a fair ReentrantLock
Lock lock = new ReentrantLock(true);
// call this to get the printer
public void acquire() {
lock.lock();
}
// call this to release the printer, so it's available for other threads
public void release() {
lock.unlock();
}
}
class Jobs implements Runnable {
// Declare isDataAvailble as volatile as you're going to change it from another thread
volatile boolean isDataAvailble;
private final Printer printer;
// constructor now takes the printer argument
Jobs(Printer printer) {
this.isDataAvailble = true;
this.printer = printer;
}
#Override
public void run() {
try {
while (isDataAvailble) {
System.out.println(Thread.currentThread()
+ "Trying to get the printer");
// get the printer
this.printer.acquire();
try {
System.out.println(Thread.currentThread()
+ "Printer acquired!");
// use it
Thread.sleep(3000);
} finally {
// Release the printer. Better to do it in finally block
// so you will release it even if some unexpected exception occurs
this.printer.release();
}
}
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I think what you are looking for is a Condition. You first need to obtain a lock, then you can check a condition. While that condition hold the thread will sleep. When the condition no longer holds the sleeping thread (or next sleeping thread) is woken up to check the condition again.
You can read more about the Condition object here: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html
It should look like this:
Acquire the printer:
synchronized (PrinterQueue.printer) {
while (PrinterQueue.printer.isUsed()) {
try {
System.out.println(Thread.currentThread()
+ "WAITING FOR PRINTER");
PrinterQueue.printer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread() + "GOT PRINTER");
PrinterQueue.printer.setUsed(true);
}
Use the printer, dummied as per your code by Thread.sleep():
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Release the printer:
synchronized (PrinterQueue.printer) {
PrinterQueue.printer.setUsed(false);
PrinterQueue.printer.notifyAll();
}
You need to use while rather than if, and you need to test the same object you're synchronized on. And use notifyAll() rather than notify().
But it isn't clear to me that you need any of this, just a synchronized block.

Categories

Resources