This question already has answers here:
Synchronizing on an object in java, then changing the value of the synchronized-on variable
(4 answers)
Closed 5 years ago.
private volatile Object obj = new MyObject();
void foo()
{
synchronized(obj)
{
obj.doWork();
}
}
void bar()
{
synchronized(obj)
{
obj.doWork();
obj = new MyObject(); // <<<< notice this line (call it line-x)
}
}
Suppose at a certain point in time, a thread t_bar is executing bar(), and another one t_foo is executing foo, and that t_bar has just acquired obj, so t_foo is, in effect, waiting.
After the sync-block in bar is executed, foo will get to execute its sync-block, right? What value of obj would it see? The old one? Or the new one set in bar?
(I would hope that the new value is seen, that's the whole point of coding it that way, but I want to know if this is a 'safe' bet)
In the exact situation you described, yes, the read of obj inside foo's synchronized block will see the new value set by the previous bar's synchronized block.
The fun part is, it doesn't always happen in that exact situation. The program is not thread safe, for example, if immediately after bar() exits, the same threads invokes another bar(), while the foo thread is locking on the old object. The bar thread locks on the new object, so the two threads are executing concurrently, both executing obj.doWork() on the same new obj.
We can probably partially fix it by
// suppose this line happens-before foo()/bar() calls
MyObject obj = new MyObject();
void foo()
while(true)
MyObject tmp1 = obj;
synchronized(tmp1)
MyObject tmp2 = obj;
if(tmp2==tmp1)
tmp2.doWork();
return;
// else retry
this at least guarantees no current invocations of obj.doWork() on the same obj, since obj.doWork() can only occur in a synchronized block that locks the exact same obj
It will behave normally as if object reference was not changed internally. Reason being that test for lock on object will be done only once. So even if object changes internally, thread will keep waiting and behaviour will remian same as if object was same [unchanged].
I tried another thing. I placed a sleep statement just after new object was created and then started the next thread and as expected both threads started working simultaneously.
See the code below.
public class ChangeLockObjectState {
private volatile Object obj = new Object();
void foo() {
synchronized (obj) {
try {
System.out.println("inside foo");
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
void bar() {
synchronized (obj) {
try {
System.out.println("inside bar");
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
obj = new Object(); // <<<< notice this line (call it line-x)
System.out.println("going out of bar");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("wait over");
}
}
/**
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
final ChangeLockObjectState test = new ChangeLockObjectState();
new Thread(new Runnable() {
#Override
public void run() {
test.bar();
}
}).start();
Thread.sleep(6000);
new Thread(new Runnable() {
#Override
public void run() {
test.foo();
}
}).start();
}
}
The new value is shown. And it works even without the making obj volatile. That's because the sychronization is still hold on the old object and provides visibility to the new value once the waiting thread (t_foo) gets inside. Here is the test:
public class Main3 {
private MyObject obj = new MyObject(1);
void foo()
{
synchronized(obj)
{
System.out.println(obj.number);
obj.doWork();
}
}
void bar()
{
synchronized(obj)
{
System.out.println(obj.number);
obj.doWork();
//force the foo thread to wait at the synchronization point
for(int i = 0; i < 1000000000l; i++);
obj = new MyObject(2); // <<<< notice this line (call it line-x)
}
}
public static void main(String[] args) throws InterruptedException {
final Main3 m3 = new Main3();
Thread t1 = new Thread( new Runnable() {
#Override
public void run() {
m3.bar();
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
m3.foo();
}
});
t1.start();
t2.start();
}
}
class MyObject {
int number;
public MyObject(int number) {
this.number = number;
}
public void doWork() {
}
}
This is unsafe and broken. Changing the object you lock on doesn't work.
When a thread tries to enter a synchronized block it first has to evaluate the expression in parens in order to figure out what lock it needs. If the lock changes after that, the thread doesn't have any way of knowing that, it eventually acquires the old lock and enters the synchronized block. At that point it sees the object and evaluates that, getting the new reference, and calls the method on it with the old (now irrelevant) lock, and without holding the new lock, even though some other thread might have the new lock held and could be executing the method on the same object concurrently.
The new value of obj will be read.
From the standard's section on Happens before:
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
From definition of shared variable:
All instance fields, static fields, and array elements are stored in heap memory. In this chapter, we use the term variable to refer to both fields and array elements.
Local variables (§14.4), formal method parameters (§8.4.1), and exception handler parameters (§14.20) are never shared between threads and are unaffected by the memory model.
The read of obj inside of the synchronized block is separate from the initial evaluation of the expression obj to determine the which object's build-in monitor to lock. The reassignment of obj will happen before the first read, but not the second. Since obj is a volatile field, that second read must see the updated value of obj.
Related
I have been assigned an exercise from my uni professor that goes as follow:
"A fence object is an object that has a collection of objects, and can wait on any of those objects is signaled. There is an add(Object) method, which adds an object to the collection. There is also an await() method: this allows to wait on any object of the collection to be signaled. Whenever the add(Object) method is called while the await() method is active, the argument of the add is put in queue. Write the source code using the following interface: ".
public interface Fence {
public void await() throws InterruptedException;
public void add(Object o);
}
So, only when the same number of notify() and objects in queue (aka the number of add(Object) ) are called, the await() terminates and the object in the queue are finally added to the collection. <- this is something I got wrong and realized after writing my code
I did make the implementation as follow:
import java.util.LinkedList;
public class FenceImpl2 implements Fence{
private LinkedList<Object> collection;
private Object mutex; ;
static boolean iswaiting = false;
public FenceImpl2() {
this.collection = new LinkedList<Object>();
this.mutex = new Object();
}
#Override
public void await() throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
try {
synchronized(mutex) {
mutex.wait();
iswaiting = true;
}
} catch (InterruptedException e) {
e.printStackTrace();
}}});
t1.start();
}
#Override
public void add(Object o) {
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
synchronized(mutex){
if(iswaiting == true) {
try {
mutex.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
collection.add(o);
}
}}});
t2.start();
}
public Object getList() throws InterruptedException {
synchronized(mutex){
System.out.println("Collection list: \n");
for(Object o : collection) {
System.out.println(o);
Thread.sleep(1000);
}
System.out.println("------- \n");
return collection;
}
}
public void notification() {
Thread thread = new Thread(()->{
synchronized(mutex){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mutex.notify();
}
});
thread.start();
}
public static void main(String[] args) throws InterruptedException {
FenceImpl2 f = new FenceImpl2();
Object o1 = 1;
Object o2 = 2;
Object o3 = 3;
Object o4 = 70;
f.add(o1);
System.out.println("Add 1");
f.add(o2);
System.out.println("Add 2");
f.add(o3);
System.out.println("Add 3");
f.await();
System.out.println("Await active ");
f.add(o4);
System.out.println("Aggiungo 70 - Shouldn't appear. Forced in queue");
f.getList();
f.notification();
System.out.println("Notify() sent - 70 should now appear in the collection");
f.getList();
}
}
After submitting it to my professor I have been told two things:
The synchronization is not correct: the await "unlocks" after the first notify and that shouldn't happen because it doesn't wait for the other (if any) objects that are in queue to be notified.
^Let me say I know how to fix that easily but
Although it's a minor mistake, the methods await, add and notification SHOULD NOT be done using asynchronous dedicated threads.
Here it finally comes my problem. How am I supposed to use wait() on a lock object and then notify() if I am not using dedicated threads?
I tried removing the threads but obviously as soon as I'm calling mutex.wait() the program locks and the code right after that calls the notification method is not reached.
Why did my professor tell me using threads is wrong?
How can I use a wait() and then call a notify() in two separate methods without having the program lock?
Here's an example of what I mean:
public class testw {
private Object mutex;
boolean condition = false;
public testw() {
this.mutex = new Object();
}
public void startWait() {
synchronized(mutex) {
try {
Thread.sleep(1000);
condition = true;
while(condition == true) {
System.out.println("Waiting!");
mutex.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void sendNotify() {
synchronized(mutex) {
try {
Thread.sleep(3000);
System.out.println("Notify!, not waiting anymore");
condition = false;
mutex.notify();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
testw t = new testw();
t.startWait();
t.sendNotify();
}
Without using threads, when I startWait() is called the main thread goes in wait, but there's no way that sendNotify() to be called and the programs freezes. Is there a way to do this without using threads or am I missing something?
Thank you very much.
I have been told...Although it's a minor mistake, the methods await, add and notification SHOULD NOT be done using asynchronous dedicated threads.
The whole point of a method named await() is that it should not return until the event that the caller wants to wait for has happened.
Your await() method doesn't wait. It creates a new thread and then it immediately returns. The new thread waits for something, but after that it just dies without doing anything useful. The new thread might as well not exist at all.
Your add(o) method doesn't make a whole lot of sense either. I'm not even sure what you were trying to do with it, but I think you need to take a step back, and try to explain to the duck why you thought that either of those two methods should create a new thread.
How am I supposed to use wait() on a lock object and then notify() if I am not using dedicated threads?
The Oracle "Guarded Blocks" tutorial is an oldie but a goodie. If you work through it to the end, it should give you a pretty clear idea of how and why and when to use wait() and notify().
https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
Let's say I have below code
public class ContinueIfCannotLock implements Runnable
{
static List<LockingObject> lockObjects = new ArrayList();
#Override
public void run()
{
for(LockingObject obj : lockObjects)
{
synchronized ( obj )
{
// do things here
}
}
}
}
and the LockingObject is just and empty class. Also let's assume before these threads start we have 100 of objects in the LockingObject list.
So how can I let a thread to continue to next object in the list if it cannot acquire the lock to the current element. So that no thread (at least until all the objects are not locked by a thread) is waiting inside the loop.
Try using Thread.holdsLock(Object obj),
Returns true if and only if the current thread holds the monitor lock on the specified object.
~Thread (Java Platform SE 8)~
static List<LockingObject> lockObjects = new ArrayList();
#Override
public void run(){
for(LockingObject obj : lockObjects){
if(Thread.holdsLock(obj)){
continue; //continue the loop if object is locked.
}
synchronized(obj){
// do things here
}
}
}
}
You May use locks:
static List<ReentrantLock> lockObjects;
public static void init(){
lockObjects = new ArrayList<>(100);
for(int i = 0; i<100;i++){
lockObjects.add(new ReentrantLock());
}
}
#Override
public void run()
{
for(LockingObject lock : lockObjects)
{
if(lock.tryLock()){
try{
//dostuff
}finally{
lock.unlock();
}
// break if you only want the thread to work once
break;
}
}
}
If your only goal with this was to have a maximum of 100 threads working at the same time, you could also use a Semaphore which is a lock that let's multiple threads lock it up to a specified value.
Here is my code:
public class ThreadDemo {
public static void main(String args[]) throws Exception {
Printer[] printers = new Printer[5];
printers[0] = new Printer("#base");
printers[1] = new Printer("#try");
printers[2] = new Printer("!test");
printers[3] = new Printer("^hello");
printers[4] = new Printer("*world");
for (Printer x : printers) {
x.start();
}
try {
for (Printer y : printers) {
y.join();
}
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
class Printer extends Thread {
public Printer(String name) {
super(name);
}
public void run() {
print();
}
public synchronized void print() {
for (int i = 0; i < 10; i++) {
System.out.print(getName().charAt(0));
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println(e + " occured");
}
}
}
}
It results in
#^!#**#^!#*##!^#*#^!#^!*#^*#!##!#*^##^!*!#^#*##*^!
My expectation is that all symbols would be serialized as #####^^^^^ based on which thread starts first.
Calling sleep() would let other threads to proceed until sleeptime of current thread , but i guess that should not be the case with synchronized method.
The synchronised doesn't come into play here.
That keyword makes sure that you can't invoke the same method on the same object in parallel.
You are invoking it on different objects, therefore the result would be the same even without the keyword in place!
( I rather assume that the result you see is in fact caused by using println() here. That is a "really slow" operation that introduces "de facto" synchronisation when used by threads that are super-quick doing all their other work. I am trying to find some additional information about that, but that might take some more time )
The issue with your code or I would say your expectation is that the method print is synchronized at the object level and you are creating new thread objects, starting the thread and calling this method.
So in this case, each method is synchronized on each individual thread object. To achieve the behavior you expect, we can make the print method static and see the behavior change. You will get the expected result because then, the method print is synchronized on a single instance of Printer class lock. So even if different threads instance are calling this method, because there is a single lock for class, thread execution happens sequentially.
public static synchronized void print() {
for (int i = 0; i < 10; i++) {
System.out.print(Thread.currentThread().getName().charAt(0));
try {
sleep(100);
} catch (InterruptedException e) {
System.out.println(e + " occured");
}
}
}
#SolomonSlow - So it has to be corrected as 'No Synchronized methods' can be called on the same object at same time ?
There is only one thing you will ever need to know about a synchronized instance method. You need to know that this...
synchronized void Foobar() { ... }
...Is just a shortcut way of writing a synchronized block.
void Foobar() {
synchronized (this) {
...
}
}
Both of those method declarations do exactly the same thing. So, everything you know or learn about how synchronized blocks behave can be applied to synchronized methods too.
The most important thing to know about synchronized blocks is, "No two threads can ever be synchronized on the same object at the same time." If you understand that, and if you know how a synchronized method is just a shortcut for a synchronized block, then you can answer your own question.
I observed a scenario where use of synchronized method or synchronized block producing different results.
From below code:
class Callme {
void call(String msg) {
System.out.print("[" + msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("]");
}
}
class Caller implements Runnable{
String msg;
Callme target;
Thread t;
public Caller(Callme target, String msg) {
this.target = target;
this.msg = msg;
t = new Thread(this, "Caller thread");
t.start();
}
#Override
public void run() {
synchronized(target) {
target.call(msg);
new Callme().call(msg);
}
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Callme obj = new Callme();
new Caller(obj, "thread1");
new Caller(obj, "thread2");
new Caller(obj, "thread3");
Thread.currentThread().join();
}
}
When I use the synchronized block in the Caller::run method the ouput is synchronized as below:
[thread1]
[thread1]
[thread3]
[thread3]
[thread2]
[thread2]
But when I use the synchronized method for the Callme::call method, instead of synchronized block, the output is not synchronized:
[thread1]
[thread1[thread2]
]
[thread3[thread2]
]
[thread3]
My Expectation is the output should not be synchronized on both cases because I am using different objects when calling the "Callme::call" method
This made me question my understanding of the Synchronized block concept?
A synchronized method is equivalent to a synchronized(this)-block for the length of the entire method, however your code is using synchronized(target), and target is a shared instance of Callme. In other words: the object being synchronized on is different, so the behavior is not the same.
In the case you use synchronized(target), it means that all threads synchronize on the same instance of Callme so their behavior is serial: a thread will hold the monitor of that Callme instance for the whole duration of the Caller.run method, so in effect the threads are executed one after the other.
In the case of a synchronized method, the threads each synchronize on their own instance of Caller, so in effect there is no serialization (except for the writes to System.out).
Some additional remarks:
Calling Thread.currentThread().join() is a bad idea, because it will wait on itself
In general don't create and start Thread instances in the Runnable implementation that is going to be run by that thread: you lose access to the thread. Especially don't do this in the constructor, because you are publishing a partially constructed object to the Thread, which is not a big problem in this code, but might lead to subtle bugs in more complex applications.
I'm trying to have a Thread2 wait for a String and Thread1 to notify on String update, I do synchronize The String object as code below shows, But I still get IllegalMonitorStateException Here's my code
public class Class1{
String string = "";
public Class1(){
Thread t1 = new Thread(){
public void run(){
synchronized(string){
string = "Something"; string.notifyAll(); //This is the line that throws an IllegalMonitorStateException
}
}
};
Thread t2 = new Thread(){
public void run(){
synchronized(string){
try{
string.wait();
}catch(Exception e){
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}
}
There's nothing in StackTrace except highlighting string.notifyAll()
Your code contains a data race because it accesses the mutable string variable outside of a synchronized block. Specifically, this happens on the line synchronized(string). While dereferencing string to reach the object whose monitor will be locked, the thread does not already hold a lock on that object. Therefore you have no guarantee which object it will acquire a lock on.
The fact that you mutate the string variable means that it now points to some other object. When the next thread acquires a lock on that new object, it will not benefit from any happens-before relationship because it is the first thread to ever acquire a lock on it. Mutual exclusion will not be guaranteed, either, because there may be arbitrarily many threads, each locking a different String instance without contention.
Combining the two phenomena described above we can also see that there is no guarantee that the object reached on the line synchronized(string) will be the same one as the one reached from within the synchronized block. Once it happens that this is indeed a different object, your IllegalMonitorStateException ensues.
In summary, the situation is very similar to the synchronized block not existing at all.
All of the above problems can be avoided if you keep to the best practice of using dedicated final variables to refer to objects used for locking. In a nutshell, and fixing the compilation errors in your example, this is what you would have to write:
static String string = "";
static final Object lock = new Object();
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
synchronized (lock) {
... update the string variable ...
lock.notifyAll();
}
}
};
Thread t2 = new Thread() {
public void run() {
synchronized (lock) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
t2.start();
t1.start();
}