Can't relase the lock with notify - java

I've got a test on java thread coding but i have some basic problem.. after hours of trying and searching I decided to try there!
I can't understand why my wait is still locked even after my notify :
Here you can find my code:
public class Mymain {
public static void main(String[] args) {
for( int i=0;i<100;i++){
new ThreadClass(i).start();
}
}
}
public class ThreadClass extends Thread {
static boolean ok = false;
int id;
public ThreadClass(int i) {
id = i;
}
public void run() {
System.out.println("Thread start " + id);
Last.toDo(id);
if (id == 5)
try {
waiting();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (id != 5)
awaking();
System.out.println("thread end " + id);
}
private synchronized void awaking() {
// TODO Auto-generated method stub
if (ok) {
System.out.println("i'm " + id + " and i'm Awaking 5");
ok = false;
notify();
System.out.println("I did the notify and i'm " + id);
}
}
private synchronized void waiting() throws InterruptedException {
System.out.println("Sleeping");
ok = true;
wait();
System.out.println("Awake 5");
}
}
Result
Then it starts looping or it goes in dead lock not sure.. it should just stop the thread with id=5 and then the next thread should re-start the id = 5.. but thread 5 never wake up after the notify...
In the result as you can see I got 2 threads trying to wake up the thread 5 and thread 5 is always waiting since the start^^

The issue is that you are not calling notify() on the same object that you called wait() on. In particular, thread 5 is calling wait() on itself, but thread 8, for example, is calling notify() on itself, not on thread 5. As a result, thread 5 is never getting notified.
Also, you need to make the ok variable volatile to ensure that when one thread sets it, the other threads can see the change. This isn't causing you a problem in this particular case, but it could cause a problem in other cases.

Why you don't use notifyAll() method? When you invoke notify(), it means that only one thread will change a status from waiting to runnable, but there can be the situations when you have more than one thread and other threads which are waiting in the line as well, they will not receive this notification. In my opinion it is preferable to use notifyAll.

i can't understand why my wait is still locked even after my notify :
Wait and notify work when the same object instance is used. If you for example have:
String x1 = "...";
String x2 = "...";
and thread #1 does:
synchronized (x1) { x1.wait(); }
and thread #2 then does:
synchronized (x2) { x2.wait(); }
Then thread #1 will still be waiting because the notify was only for x2. In your example, the thread with id 5 is waiting on its own instance of ThreadClass since you are using method synchronization. Then when other threads call awaking() they too are calling notify on their instances of ThreadClass. If you want thread #5 to see the other thread's notify then they should share a lock object.
Maybe something like:
final Object lock = new Object();
for (int id = 0; id < 100; id++){
new ThreadClass(id, lock).start();
}
...
public class ThreadClass extends Thread {
private final Object lock;
...
public ThreadClass(int id, Object lock) {
this.id = id;
this.lock = lock;
}
...
private void awaking() {
...
synchronized (lock) {
lock.notify();
}
...
}
private void waiting() throws InterruptedException {
...
synchronized (lock) {
lock.wait();
}
...
}
}

Look I did a few changes to your code:
You can't just notify() , you'll notify to this. And you can't just wait() , you'll wait forever. You have to use these function over an Object, so i added an Integer object (just to show you - you'll have to choose the right object).
You have yo understand between synchronized and static synchronized. A quick search would lead you to a perfect answer.
Why function waiting() is synchronized? only thread number 5 calls it.
When calling to an Object.notify() / Object.wait(), you have to declare a synchronized block over the object.
Here's some code:
public class Threads {
public static void main(String[] args) {
Integer intObject = new Integer(0);
for( int i=0;i<100;i++){
new ThreadClass(i, intObject).start();
}
}
}
class ThreadClass extends Thread {
static boolean ok = false;
int id;
Integer intObject;
public ThreadClass(int i, Integer intObject) {
id = i;
this.intObject = intObject;
}
public void run() {
System.out.println("Thread start " + id);
//Last.toDo(id);
if (id == 5)
waiting();
else
awaking(this);
System.out.println("thread end " + id);
}
private static synchronized void awaking(ThreadClass t) {
if(ok) {
System.out.println("i'm " + t.id + " and i'm Awaking 5");
ok = false;
synchronized (t.intObject) {
t.intObject.notify();
}
System.out.println("I did the notify and i'm " + t.id);
}
}
private void waiting(){
System.out.println("Sleeping");
ok = true;
synchronized (intObject) {
try {
intObject.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Awake 5");
}
}

Related

Java - Synchronized block not working

I have the following class
public class OddPrinter implements Runnable {
public void run() {
try {
for (int n = 0; n <= 10; n++) {
if((n%2) != 0)
System.out.println(" Odd Thread" + n);
Thread.sleep(1000);
}
System.out.println("Exiting Odd Thread");
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
And the main class which tries to have a synchronized access to the object of the above class
public class MultiThread {
public static void main(String[] args) {
Thread t1, t2;
OddPrinter first = new OddPrinter();
synchronized(first)
{
t1 = new Thread(first, "firstThread");
t1.start();
t2 = new Thread(first, "secondThread");
t2.start();
}
}
}
I am getting an output as follows
Odd Thread1
Odd Thread1
Odd Thread3
Odd Thread3
Odd Thread5
Odd Thread5
Odd Thread7
Odd Thread7
Odd Thread9
Odd Thread9
Exiting Odd Thread
Exiting Odd Thread
A synchronized block ensures
that a call to a method that is a member of object occurs only after the current thread has
successfully entered object’s monitor.
According to the above reference ( Java2 - The Complete Reference - Herbert Schildt), I am expecting an output where one thread waits for the other to finish the printing of the odd numbers. But that is not happening. What is the issue here?
A synchronized block ensures that a call to a method that is a member of object occurs only after the current thread has successfully entered object’s monitor.
No it doesn't. It ensures that a synchronized method that is an instance member of the class of the object occurs only after the current thread has exited the block, if invoked on the same object, and that another synchronized block on the same object doesn't execute until this block exits.
Several of those conditions don't apply to your code.
I am expecting an output where one thread waits for the other to finish the printing of the odd numbers.
Wait for thread t1 to complete before starting thread t2:
t1.start():
t1.join();
t2.start();
You only synchronized one access. The other threads don't synchronize on the object, so nothing is blocked. Even if they did and were, once both threads have started, the code block in main completes and the threads are free to run anyway.
Furthermore, the synchronization you used in main happens in advance of any other threads that might conflict, and the main thread doesn't need any shared state in the first place, so the synchronization there is useless.
Study the concepts "critical section", "memory barrier", and Java's "happens-before". Buy and study the book Java Concurrency in Practice, by Brian Goetz, et al.
synchronized lock should be put inside your runnable code, not your main method.
I think you can either put synchronize to your method
public class OddPrinter implements Runnable {
public synchronized void run() {
try {
for (int n = 0; n <= 10; n++) {
if((n%2) != 0)
System.out.println(" Odd Thread" + n);
Thread.sleep(1000);
}
System.out.println("Exiting Odd Thread");
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
Or, you can put it in your method like this
public class OddPrinter implements Runnable {
static Object lock;
public void run() {
synchronized (lock) {
try {
for (int n = 0; n <= 10; n++) {
if((n%2) != 0)
System.out.println(" Odd Thread" + n);
Thread.sleep(1000);
}
System.out.println("Exiting Odd Thread");
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
You need to change OddPrinter where you can put synchronized block and use a single lock to synchronized so at time one thread can enter to critical section.And remove the synchronized block from main method.
public class OddPrinter implements Runnable {
private Object lock;
public OddPrinter(Object lock) {
this.lock = lock;
}
public void run() {
synchronized (lock) {
for (int n = 0; n <= 10; n++) {
if ((n % 2) != 0)
System.out.println(" Odd Thread" + n);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Exiting Odd Thread");
}
}
}
public class MultiThread {
public static void main(String[] args) {
Thread t1, t2;
Object object=new Object();
t1 =new Thread(new OddPrinter(object),"firstThread");
t1.start();
t2 =new Thread(new OddPrinter(object),"secondThread");
t2.start();
}
}
This is definitely not the way synchronization should be implemented. In your implementation there is no monitor/locks or notify implementation since the lock acquired is soon out of scope of main thread's control.
It's completely wrong to do this way. In case you wanted to do something exclusive, the lock should be locked inside your thread -- not outside!.
public class MyThread implements Runnable {
private Object mutex;
public MyThread(Object sharedObject) {
this.mutex = sharedObject;
}
public void run() {
// Method 1 -- Class reference used as the mutex: locks and executes only one instance between the blocks
synchronized (MyThread.class) {
}
// Method 2 -- All the same instance of the object reference used as mutex receives a blocked interference, and only one thread is executed.
synchronized (mutex) {
}
}
// Method 3 - Only one synchronized method inside the class is executed at any given point in time.
private synchronized void produce() {
}
// Method 3 (Contd.) - Added in conjunction with produce() call
private synchronized void consume() {
}
}

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.

NotifyAll not working properly: program to control thread execution order - print integers sequentially

First of all, this is not a homework.
I have written a piece of code so that:
Thread-1 prints 1,4,7,... (diff is 3)
Thread-2 prints 2,5,8,...
Thread-3 prints 3,6,9,...
And the final output should be:
1,2,3,4,5,6,7,8,9,...
Here's the code that works wonderfully well:
package threadAlgo;
public class ControlOrder {
volatile Monitor monitor = new Monitor();
public static void main(String[] args) {
ControlOrder order = new ControlOrder();
Thread one = new Thread(new Task(order.monitor, 1));
one.setName("Thread-1");
Thread two = new Thread(new Task(order.monitor, 2));
two.setName("Thread-2");
Thread three = new Thread(new Task(order.monitor, 3));
three.setName("Thread-3");
one.start();
two.start();
three.start();
}
}
class Monitor {
int threadNumber = 1;
}
class Task implements Runnable {
private Monitor monitor;
private int myThreadNumber;
private int currentCount;
Task(Monitor monitor, int myThreadNumber) {
this.monitor = monitor;
this.myThreadNumber = myThreadNumber;
this.currentCount = myThreadNumber;
}
#Override
public void run() {
while (true) {
while (monitor.threadNumber != myThreadNumber) {
synchronized (monitor) {
try {
monitor.wait(100); //DOESN'T WORK WITHOUT THE TIMEOUT!!!
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized (monitor) {
if (monitor.threadNumber == myThreadNumber) {
System.out.println(Thread.currentThread().getName() + ": " + currentCount);
currentCount = currentCount + 3;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (myThreadNumber == 3) {
monitor.threadNumber = 1;
} else {
monitor.threadNumber = myThreadNumber + 1;
}
monitor.notifyAll();
}
}
}
}
The only problem is that if I use wait() instead of wait(timeout), then the thread halts.
UPDATE:
Wait condition (while loop) should be inside synchronized block. A lesson for beginners, including me.
You should always
perform notifyAll/notify in conjunction with a change in state.
check the state change before using wait() in a loop.
If you call notify() and no wait() is waiting, then the signal is lost, so unless you check a state change, (or timeout) you can block forever waiting for a signal which doesn't change.

How can I run a thread after another thread has completed its actions

I am trying to simulate a parking lot entry system that contains 2 floors of 20 spaces and 2 entries and 2 exits. I am using Threads in Java, and I have tried to use thread.wait() and thread.sleep but they don't help in making a thread run after another thread is over.
This is what I have come up with so far:
ShardedDataThread.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class SharedDataThread extends Thread {
private SharedData mySharedData;
private String myThreadName;
public int L1 = 20;
public int L2 = 20;
//Setup the thread
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
SharedDataThread(String name, SharedData sharedstuff) {
super(name);
mySharedData=sharedstuff;
myThreadName=name;
}
//This is called when "start" is used in the calling method
public void run() {
while(true){
System.out.println("Entry or Exit?");
String input = null;
try {
input = br.readLine();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
if (input.equalsIgnoreCase("entry")) {
try {
// Acquire the lock using the acquireLock() method
// The thread will pause here on wait() until it gets a lock
mySharedData.acquireLock();
//use park method to occupy one space
this.park(); // Increment the number of reads
mySharedData.releaseLock();
}
catch(InterruptedException e) {
System.err.println("Failed to get lock when reading:"+e);
}
}
else {
try {
mySharedData.acquireLock();
System.out.println(myThreadName+" is writing");
exit(); // INCREMENT ONE SPOT
mySharedData.releaseLock(); // releases the lock
}
catch(InterruptedException e) {
System.err.println("Failed to get lock when writing:"+e);
}
}
System.out.println("L1 has : "+L1+" "+"L2 has: "+" "+L2);
}
//while ends
}
//State method
public void park() {
if (L1>0 && L1<=20){
L1= L1-1;
}
else if (L1==0 && L2<=20 && L2>0){
L2= L2-1;
}
else if (L1==0 && L2==0){
System.out.println("No Spaces Left");
}
}
public void exit() {
if (L1<20) {
L1 = L1 +1;
} else if (L2<20) {
L2 = L2+1;
}
}
public static void main(String[] args) throws InterruptedException {
SharedData mySharedData = new SharedData();
SharedDataThread myThread1 = new SharedDataThread("Entry1", mySharedData);
//SharedDataThread myThread2 = new SharedDataThread("Entry2", mySharedData);
//SharedDataThread myThread3 = new SharedDataThread("Exit1", mySharedData);
//SharedDataThread myThread4 = new SharedDataThread("Exit2", mySharedData);
// Now start the threads executing
myThread1.start();
//myThread1.join();
//myThread2.start();
//myThread2.join();
//myThread3.start();
//myThread3.join();
//myThread4.wait();
}
}
SharedData.java
public class SharedData {
private boolean accessing=false; // true a thread has a lock, false otherwise
// attempt to acquire a lock
public synchronized void acquireLock() throws InterruptedException{
Thread me = Thread.currentThread();
while (accessing) {
wait();
}
accessing = true;
}
// Releases a lock to when a thread is finished
public synchronized void releaseLock() {
//release the lock and tell everyone
accessing = false;
notifyAll();
Thread me = Thread.currentThread(); // get a ref to the current thread
}
}
This never makes any sense:
myThread1.start();
myThread1.join();
It never makes any sense to start a thread and then immediately wait for it to finish. The entire point of having threads is that different threads can be doing different things at the same time.
If there isn't anything else that the caller wants to do while myThread1 is running, then there is no reason to create myThread1. The caller should just do whatever it is that myThread1 would have done at that point.
Don't use threads to model objects in a simulation. Use threads to do work. Usually, that means, use a thread pool such as java.util.concurrent.ThreadPoolExecutor to perform tasks.
If you want your simulation to run in real time, don't use threads that sleep(). Use a scheduler such as java.util.concurrent.ScheduledThreadPoolExecutor to perform delayed tasks.
You're thinking about the problem wrong. Don't think about waiting for a thread to do something after a thread is done. Think about doing something after some work is done. That means that the work has to be waitable.

More than one thread inside synchronized methods? [duplicate]

This question already has answers here:
Entering in block with an Intrinsic Lock
(2 answers)
Closed 8 years ago.
As I red somewhere, when we have synchronized methods, only one thread can use any of those method at the same time. The problem is that I have small peace of code that looks to break this rule, and I hope some of you knows why.
import java.util.Date;
public class SyncTest extends Thread {
private int state;
public static final int STATE_STOP = 10;
public static final int STATE_DO_TASK = 2;
public static final int STATE_FREE = 0;
public void run() {
try {
while(getThisState() != STATE_STOP) {
if(getThisState() == STATE_DO_TASK) {
Thread.sleep(2000);
setState(0);
}
}
}catch(Exception ex) {
ex.printStackTrace();
}
}
public synchronized void setState(int newState) {
this.state = newState;
this.notify();
}
public synchronized int getThisState() {
return this.state;
}
public synchronized void waitForComplete(int timeoutMilisec) {
try {
while( getThisState() != STATE_FREE) {
wait(timeoutMilisec);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
SyncTest syncTest = new SyncTest();
syncTest.start();
syncTest.setState(STATE_DO_TASK);
System.out.println("Start operation: " + new Date());
syncTest.waitForComplete(30000);
syncTest.setState(STATE_STOP);
System.out.println("End operation: " + new Date());
}
}
What we have here is 'waitForComplete' method, that waits until state equals zero. While main thread waits, second thread is sleeping 5 seconds and then calls setState method. This changes 'state' variable to zero, and calls notify what unlocks waiting in main process. That seems to make sense, but the question is: How the hell it is possible that second thread executes 'setState' when on the same time main thread is inside 'waitForComplete' method. Both methods are synchronized, so it should be impossible to execute them simultaneously.
When you call wait() the thread releases its lock on the monitor, so other threads are free to enter the synchronized block.

Categories

Resources