I have two different objects but
they are equals (obj1 != obj2, but obj1.equlas(obj2))
How can I use synchronization/lock for this objects like one?
For example:
...
synchronized(obj) {
doSomething(obj);
}
...
I want to lock it if one of the equals() object already doing something in the same time.
There is no way to use just one synchronized (object) and get both objects synchronized.
The solutions is:
synchronized (obj) {
synchronized (obj2) { ......
but if you invert the order in onother thread you can get a dead lock.
or the other solution, one I suggest, is to make your obj static and use to synchronize.
what you have is meaningfully equals objects, but the reference of variable that you have for obj and obj2 are pointing for different objects.
I can't say I fully understand why this could be required, but using wrapper approach may potentially help:
public class SyncOnEquals {
public synchronized Object getSync(Object o1, Object o2)
{
if(o1.equals(o2))
return this;
else
return o1;
}
}
Test:
#org.junit.Test
public void testSyncOnEqual() {
System.out.println("syncOnEqual");
Integer o1 = new Integer(125);
Integer o2 = new Integer(125);
System.out.println("o1 == o2: "+(o1==o2));
System.out.println("o1.equals(o2): "+o1.equals(o2));
SyncOnEquals sync = new SyncOnEquals();
Thread t1 = new Thread(){
public void run()
{
System.out.println("Waiting thread "+Thread.currentThread());
synchronized(sync.getSync(o1, o2))
{
System.out.println("Working thread "+Thread.currentThread());
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println("Finished thread "+Thread.currentThread());
}
};
Thread t2 = new Thread(){
public void run()
{
System.out.println("Waiting thread "+Thread.currentThread());
synchronized(sync.getSync(o2, o1))
{
System.out.println("Working thread "+Thread.currentThread());
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println("Finished thread "+Thread.currentThread());
}
};
t1.start();
t2.start();
try{
Thread.currentThread().sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
Output:
syncOnEqual
o1 == o2: false
o1.equals(o2): true
Waiting thread Thread[Thread-0,5,main]
Waiting thread Thread[Thread-1,5,main]
Working thread Thread[Thread-0,5,main]
Finished thread Thread[Thread-0,5,main]
Working thread Thread[Thread-1,5,main]
Finished thread Thread[Thread-1,5,main]
Related
I want to use 3 threads to print A、B、C randomly,so I wrote code as below:
public class ThreadPrint4Test {
public static void main(String[] args) {
new ThreadPrint4Test().testPrint();
}
public void testPrint() {
Object lock = new Object();
new Thread(new PrintThread("A",lock),"thread-A").start();
new Thread(new PrintThread("B",lock),"thread-B").start();
new Thread(new PrintThread("C",lock),"thread-C").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
synchronized (lock) {
lock.notifyAll();
}
}).start();
}
class PrintThread implements Runnable {
private Object lock;
private String value;
public PrintThread(String value, Object lock) {
this.value = value;
this.lock = lock;
}
public void run() {
while (true) {
try {
synchronized (lock) {
lock.wait();
System.out.println(LocalTime.now() + "\t" + value);
lock.notifyAll();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
But when I test the program,it stoppted print characters after a few seconds
Using jps and jstack I found all the 3 threads are WAITING the object lock
I tested it for serveral times,and this phenomenon occurs every time.
I do not know why all the 3 threads are waiting object lock at same time
Based on my knowledge,each time one of the 3 threads will be awake and have the chance to exeute,then it will awake all the 3 threads randomly by invoking lock.notifyAll();. So the program should run continuous theoretically,But now each time I test it,it will stop print characters after a few seconds.
Could someone help analysis why this happen? Thanks in advance!
while (true) {
try {
synchronized (lock) {
lock.wait();
System.out.println(LocalTime.now() + "\t" + value);
lock.notifyAll();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Your problem is that you are calling notifyAll() immediately after calling wait(). You get to a deadlock situation where each thread is waiting. When all the threads are waiting, none of them can be notified, hence your program comes to a standstill.
According to the Concurrency tutorial, you need to wait() for a certain condition to occur. Once the condition occurs, you perform the required action (which, in your code, is printing the current time) then you call notifyAll() to inform the waiting threads that you have completed performing the required action and that they can try to perform their required action.
Explanations after the code.
import java.time.LocalTime;
public class ThreadPrint4Test {
private volatile boolean canPrint;
public void testPrint() {
Object lock = new Object();
new Thread(new PrintThread("A", lock), "thread-A").start();
new Thread(new PrintThread("B", lock), "thread-B").start();
new Thread(new PrintThread("C", lock), "thread-C").start();
}
class PrintThread implements Runnable {
private Object lock;
private String value;
public PrintThread(String value, Object lock) {
this.value = value;
this.lock = lock;
canPrint = true;
}
public void run() {
while (true) {
while (!canPrint) {
try {
synchronized (lock) {
System.out.printf("[%s] Waiting...%n", value);
lock.wait();
}
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
synchronized (lock) {
canPrint = false;
System.out.println(LocalTime.now() + "\t" + value);
canPrint = true;
lock.notifyAll();
}
}
}
}
public static void main(String[] args) {
new ThreadPrint4Test().testPrint();
try {
Thread.sleep(2000);
}
catch (InterruptedException x) {
x.printStackTrace();
}
System.exit(0);
}
}
I added a canPrint flag. When it is true, then the thread can print the current time. When it is false, the thread must wait.
When the thread can print the current time, it first sets the flag to false so that no other thread can print.
After the thread has printed the current time, it sets the flag back to true and calls method notifyAll() which causes all waiting threads to stop waiting and re-check the canPrint flag.
The first thread to awake after canPrint has been set to true, sets the flag to false which causes all other threads to wait.
Can this code deadlock with thread 1 calling one and thread 2 calling two. That is, can the acquisition of the inner lock be reordered to before the acquisition of the outer one (from the POV of the other thread)?
private final Object foo = new Object();
synchronized void one() {
// ...
synchronized(this.foo) {
// ...
}
// ...
}
synchronized void two() {
// ...
synchronized(this.foo) {
// ...
}
// ...
}
No, this will not deadlock.
When synchronized methods are called the intrinsic lock of this is locked before the method’s body is executed. Here either thread 1 or thread 2 will get to run its method, and the other one will not be able to lock on the intrinsic lock of this.foo so the owner of the lock of this will be able to lock this.foo.
So for with a Simple Test :
class LockTest implements Runnable {
public final Object foo = new Object();
boolean runOne;
public LockTest(boolean runOne) {
this.runOne = runOne;
}
synchronized void one() {
System.out.println("runnin one function");
synchronized(this.foo) {
try {
System.out.println("Enter Sleep function one");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
synchronized void two() {
System.out.println("running two function");
synchronized(this.foo) {
try {
System.out.println("enter sleep function two");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void run() {
if(runOne)
one();
else
two();
}
}
With this in a Main class :
while (true)
{
LockTest document2 = new LockTest(true);
LockTest document3 = new LockTest(false);
Thread tread1 = new Thread(document2);
Thread tread2 = new Thread(document3);
tread1.start();
tread2.start();
a++;
if(a==10)
break;
}
We are not locking and even watching with a Thread Dump everything is working Fine. Why? Because every time we are initializating a new Thread with a new object foo. But if that object is declared as static it will be a lock and the others threads need to wait. So from my test and POV. No, it can't be deadlocked.
This question already has answers here:
IllegalMonitorStateException on wait() call
(12 answers)
Closed 5 years ago.
I am trying to learn Multi threading and for practice, I am trying to print odd & even number using two thread. I have created an object which will act as a lock for the both the threads. When I try to execute it throws java.lang.IllegalMonitorStateException.
class EVENODDimpl implements Runnable {
int num;
int temp = 0;
Object lock = new Object();
public EVENODDimpl( int num) {
this.num = num;
}
public void run() {
try {
synchronized (lock) {
while(temp<num) {
temp++;
System.out.println(Thread.currentThread().getName()+" "+temp);
this.notify();
this.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Main Method:
public class EVENODD {
public static void main(String[] args) {
int i = 10;
EVENODDimpl ei = new EVENODDimpl(i);
Thread t1 = new Thread( ei,"EvenThread");
Thread t2 = new Thread( ei,"OddThread");
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You wait and notify on this, but you should wait and notify on lock because you synchronize on lock, you can't wait and notify on other object than the one on which you're synchronizing, working version:
class EVENODDimpl implements Runnable {
int num;
int temp = 0;
Object lock = new Object();
public EVENODDimpl( int num) {
this.num = num;
}
public void run() {
try {
synchronized (lock) {
while(temp<num) {
temp++;
System.out.println(Thread.currentThread().getName()+" "+temp);
lock.notify();
lock.wait();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
As it said from the javadoc
Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
This means that your methods notify and wait should own monitor. Or in other words the object that is calling these method must be synchronized. Your this object is not synchronized. That's why you get this exception. Call this method from lock object in your case.
Your logic is still wrong but it is up to you to explore that.
java.lang.IllegalMonitorStateException Exception occur because you are using notify method on the object this.notify() but that Object is not synchronized.
Replace synchronized (lock) with this: synchronized (this)
public class UThread implements Runnable {
Object o;
UThread(Object o) {
this.o = o;
}
#Override
public void run() {
synchronized (o) {
System.out.println("inside before change" + Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (Exception er) {
}
o = new Object();
System.out.println("inside after change" + Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (Exception er) {
}
}
System.out.println("outside " + Thread.currentThread().getName());
}
}
public class main {
public static void main(String str[]) {
Object o = new Object();
UThread uThread = new UThread(o);
Thread th = new Thread(uThread);
UThread uThread2 = new UThread(o);
Thread th2 = new Thread(uThread2);
th.start();
try {
Thread.sleep(1000);
} catch (Exception er) {
}
th2.start();
}
}
When we execute the code it print
inside before changeThread-0
inside after changeThread-0
outside Thread-0
inside before changeThread-1
inside after changeThread-1
outside Thread-1
So why second thread not taken the lock on o when I change the object.
Assigning a reference does nothing to the underlying object. All it does is copy the reference value without touching or altering the object itself. It doesn't for example, release a lock nor should it.
e.g.
Object o2 = o;
synchronized(o) {
o = new Object();
// o2 is still locked
}
// o2 is not locked
The second thread has requested a lock for the original object referenced by the o variable (the one created in your main method and passed to the constructor of the two UThread instances).
Changing the value of o inside the synchronized block of the first thread doesn't change the fact that this thread already locked the original object referenced by o, which the second thread is also waiting to lock.
I have a following program:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleWaitNotify implements Runnable {
final static Object obj = new Object();
static boolean value = true;
public synchronized void flag() {
System.out.println("Before Wait");
try {
obj.wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
System.out.println("After Being Notified");
}
public synchronized void unflag() {
System.out.println("Before Notify All");
obj.notifyAll();
System.out.println("After Notify All Method Call");
}
public void run() {
if (value) {
flag();
} else {
unflag();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(4);
SimpleWaitNotify sWait = new SimpleWaitNotify();
pool.execute(sWait);
SimpleWaitNotify.value = false;
SimpleWaitNotify sNotify = new SimpleWaitNotify();
pool.execute(sNotify);
pool.shutdown();
}
}
When I wait on obj, I get the following exception Exception in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException: current thread not owner for each of the two threads.
But if I use SimpleWaitNotify's monitor then the program execution is suspended. In other words, I think it suspends current execution thread and in turn the executor. Any help towards understanding what's going on would be duly appreciated.
This is an area1 where the theory and javadoc seem straightforward, and since there aren't many examples, conceptually left a big gap in me.
You're calling wait and notifyAll on obj, but you're synchronizing on this (because you've got synchronized methods).
In order to wait or notify, you need to "own" the monitor first. Unsynchronize the methods, and synchronize on obj instead:
public void flag() {
System.out.println("Before Wait");
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
}
System.out.println("After Being Notified");
}
public void unflag() {
System.out.println("Before Notify All");
synchronized (obj) {
obj.notifyAll();
}
System.out.println("After Notify All Method Call");
}
Either synchronize on obj, or call wait and notify on this. The calling thread must hold the monitor of the same object on which these methods are called.
For example,
synchronized void flag() {
System.out.println("Before Wait");
try {
wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
System.out.println("After Being Notified");
}
In this example, the lock is held on this (when the modifier synchronized is used on a instance method, the monitor of the instance is acquired). So, the wait() method may be invoked on the implied instance this.
In order to coordinate the two threads, they need to share the same lock. The original version had a static obj that could be used as a lock, but it wasn't used in the synchronized blocks. Here is a better example:
class SimpleWaitNotify implements Runnable {
private final Object lock;
private final boolean wait;
SimpleWaitNotify(Object lock, boolean wait) {
this.lock = lock;
this.wait = wait;
}
public void flag() {
synchronized (lock) {
System.out.println("Before Wait");
try {
lock.wait();
System.out.println("After Being Notified");
} catch (InterruptedException ex) {
System.out.println("Thread interrupted");
}
}
}
public void unflag() {
synchronized(lock) {
System.out.println("Before Notify All");
lock.notifyAll();
System.out.println("After Notify All Method Call");
}
}
public void run() {
if (wait) {
flag();
} else {
unflag();
}
}
public static void main(String[] argv) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(4);
Object shared = new Object();
SimpleWaitNotify sWait = new SimpleWaitNotify(shared, true);
pool.execute(sWait);
SimpleWaitNotify sNotify = new SimpleWaitNotify(shared, false);
pool.execute(sNotify);
pool.shutdown();
}
}
Rather putting the direct statement pool.shutdown(), try as below.
while (!service.isTerminated())
{
service.shutdown();
}
So it will wait for till all the threads execution completes.