What happens, when two threads try to access a synchronized block?
Will one of the threads be queued somewhere and access the thread later, or will the thread give up if the trial fails?
Assuming you mean a synchronized block, one thread will manage to acquire the monitor, and the other thread will block until the monitor is released.
See section 14.19 and section 17.1 of the JLS for more details, including:
The synchronized statement (§14.19) computes a reference to an object; it then attempts to perform a lock action on that object's monitor and does not proceed further until the lock action has successfully completed. After the lock action has been performed, the body of the synchronized statement is executed. If execution of the body is ever completed, either normally or abruptly, an unlock action is automatically performed on that same monitor.
(Emphasis mine.)
If you need any other semantics - e.g. timeouts - you should use one of the the types in the java.util.concurrent.locks package, so that you can use methods such as tryLock() and tryLock(long time, TimeUnit unit).
Will one of the threads be queued somewhere
Yes, It's queued in JVM and waits until runnig thread frees the lock.
will the thread give up if the trial fails
No, it keeps on trying till JVM is alive. but not trying during while another thread in running the synchronized code.(unless a timeout is specified)
Lets say ThreadA and ThreadB are trying for a synchronized block sb and ThreadB succeeds. Now, ThreadA will wait till ThreadB finishes. in the mean time, suppose ThreadC comes for sb. it sees that the block is being run by some thread and waits in same queue with ThreadA. When ThreadB finishes either ThreadA or ThreadC is given a chance to execute.
So, technically, it's NOT a queue but a similar datastructure.
One of them will wait, forever if necessary (such as the first thread executing an infinite loop), though that would be a rather bad design. There are no timeouts on code execution synchronisation.
From the JLS:
A synchronized statement acquires a mutual-exclusion lock on behalf of the executing thread, executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock.
If synchronized block is being executed by another thread then both thread will wait. Otherwise , one thread will be allowed to work upon and another will wait until first thread completes its job.
Related
Is it possible for the thread scheduler to unschedule a thread holding the lock to a synchronized block and is in the middle of executing it? If yes then does the unscheduling leads to thread releasing the lock? Assume thread doesn't call method such as wait/yield etc.
I have been trying to understand how synchronized block helps in read-update-write operation? If the thread which enters the synchronized block can't be unscheduled then it's easier to understand but if it can be then the issue of visibility comes as it might be the case that variable has been updated but not written to the main memory by thread and thread scheduler unschedules it and other thread gets the lock and updated the variable in the main memory.
Is there any info. in JLS regarding the same?
Is it possible for the thread scheduler to unschedule a thread holding [a lock]?
Yes, that can happen preemptively in many scheduling algorithms. It must happen if the thread makes a blocking system call (e.g., to wait for input).
If yes then does the unscheduling leads to thread releasing the lock?
Absolutely not! That would defeat the purpose of locking, and it would break most multi-threaded programs.
Takeaway: Keep your critical sections as short as possible! Don't let threads B, C, D, and E all get blocked waiting for thread A to release some lock when thread A is blocked performing a long computation (or worse, waiting for input).
I'm learning about multiple threading in Java. Following is demo code, and I'm curious about the usage of Thread.yield() inside of the function.
Isn't it a synchronized function, which cannot be called until the running task finishes its work on it? Then what is the difference between inserting Thread.yield() into this block and not?
Demo code:
public class SynchronizeEvenGenerator {
private int currentEvenValue = 0;
/**
* Generate even and return it
* #return
*/
public synchronized int next() {
++currentEvenValue;
Thread.yield();
++currentEvenValue;
return currentEvenValue;
}
}
What will happen if Thread.yield() is called in a synchronized function?
As the javadoc for Thread.yield() states:
"[This is a] hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint."
So there are two possibilities:
Nothing happens; i.e. the yield() call returns immediately.
Another thread is scheduled and gets to execute. Eventually, this thread is rescheduled and the yield() call returns.
One thing does not happen. The thread does not relinquish the mutex. Any other thread that happened to be blocked waiting to acquire the mutex will remain blocked.
Isn't it a synchronized method, which cannot be called until the running task finishes its work on it?
Thread.yield is not a synchronized method. (And even if it was, it would be locking the Thread object, not the lock that the synchronized block is currently holding.)
So, in your example, a call to next() is guaranteed to increment the counter by exactly 2. If some other thread calls the next() method, the second call will remain blocked until (at least) after the first call returns.
The javadoc also says this:
"It is rarely appropriate to use this method."
Another question: Will it become an deadlock for thread scheduling
No. The thread that called yield() will eventually be rescheduled.
(Deadlock is a very specific phenomenon (see Wikipedia article) that can only occur when a lock is acquired. When a thread yields, it neither acquires or releases locks, so it cannot cause a deadlock.)
Now, when a thread yields, it might be a long time before it gets scheduled again, especially if there are lots of other runnable threads at the same or higher priority. The net result is that other threads waiting to acquire the lock could held up for a long time. This can unduly increase contention and congestion. But eventually, the yield() call will return, the next() call will return and another thread will be able to acquire the lock.
In short: calling yield() while holding a lock is bad for performance, but it won't directly cause a deadlock.
As the javadoc says, calling yield() is rarely appropriate.
Isn't it an synchronized function which cannot be called until the running task finish it's work on it ?
It can't be running in another thread for the same object.
Then what is the diff between insert Thread.yield() into this block and not ?
The CPU which is running the thread could be context switched to another available thread for any process on the system.
If there is no waiting thread to run, it will make it slower by about 15 - 30 micro-seconds.
c.f. wait(0) which can allow another thread to obtain the lock.
From Programming Language Pragmatics, by Scott
To resume a thread that is suspended on a given object, some other
thread must execute the predefined method notify from within a
synchronized statement or method that refers to the same object. Like
wait, notify has no arguments. In response to a notify call, the
language run-time system picks an arbitrary thread suspended on the
object and makes it runnable. If there are no such threads, then the
notify is a no-op. As in Mesa, it may sometimes be appropriate to
awaken all threads waiting in a given object; Java provides a built-in
notifyAll method for this purpose.
If threads are waiting for more than one condition (i.e., if their waits are embedded in dissimilar loops), there is no guarantee that
the “right” thread will awaken. To ensure that an appropriate thread
does wake up, the programmer may choose to use notifyAll instead of
notify. To ensure that only one thread continues after wakeup, the
first thread to discover that its condition has been satisfied must
modify the state of the object in such a way that other awakened
threads, when they get to run, will simply go back to sleep.
Unfortunately, since all waiting threads will end up reevaluating
their conditions every time one of them can run, this “solution” to
the multiple-condition problem can be quite expensive.
When using notifyAll, all the awaken threads will contend to reacquire the lock, but only one can reacquire the lock, then return from wait() and then reevaluate the condition. So why does it say that "all waiting threads will end up reevaluating their conditions every time one of them can run"?
How does the thread, which reacquires the lock and rechecks that the condition become true, "modify the state of the object in such a way that other awakened threads, when they get to run, will simply go back to sleep"?
Thanks.
So why does it say that "all waiting threads will end up reevaluating their conditions every time one of them can run"?
After it will reacquire and release the lock a different thread will aquire it and run. This will continue until they all do that.
How does the thread, which reacquires the lock and rechecks that the condition become true, "modify the state of the object in such a way that other awakened threads, when they get to run, will simply go back to sleep"?
All the threads will have something like:
while (condition) {
wait();
}
The notifyAll() caller will set condition to false before calling it and then the awakened thread will exit the while loop and before it returns and releases it will do:
condition = true;
All the other threads will awaken, check the condition, stay in the while loop and call wait() (go back to sleep).
Additionally, you should use explicit locking mechanism because it allows you to have multiple conditions and condition queues for a single lock, which will enable you to use signal() instead of signalAll(). And that has better performance and less contention.
Condition API
Synchronized blocks in Java is a great feature when working in multiple threads, which is pretty often. I know most of how they work, but would like to be more sure of how they work when combined with wait and notify(All).
Normally when one thread enters an synchronized block, no other thread can enter this block until the first thread has left. This however is not the case when calling wait on the synchronized object. If it did, another thread would not be able to call notify(All), which requires synchronization with the object before it is called.
So does the call to wait take the call out of the synchronization? Or does java just make an exception if it finds notify(All) within a different block? Also when calling wait from one synchronized block and then notify(All) from another, does one thread wait for the other to finish before continuing, if so, which one?
Now I could setup a quick test to answer most of this, that I am aware of. But it is not going to answer the more technical stuff, which I am sure that someone here can. I am not just interested in the what and when, but also the why. Tried searching for some documented info, but could not find anything useful about wait/notify(All).
EDIT:
If others should be interested, this is the test result. If we have Thread1, Thread2 and Thread3 where the first two waits to be release and the third is the one to release them, the order will go like this.
Thread1 enters and calls wait()
Thread2 enters and calls wait()
Thread3 enters and calls notifyAll()
Thread3 finishes, always
The waiting threads however has no specific order. Which one is executed first, is completly random and has nothing to do with the order in which they called wait(). The thread calling notify(All) however will always finish before any waiting threads continues.
Yes, it is somehow special. wait releases the lock acquired in the synchronized block and and suspends it's thread (the thread that acquired the lock) which means other threads will be allowed to acquire the lock and modify the state.
Now notify or notifyAll will wake up the thread/s that were asleep and they reacquire the lock
Considering the fact that wait() can only be called in a synchronized context which subsequently release the monitor until a notify/nofityAll has been called on the same object by another thread,
Assume Thread A is blocking on a wait() which results in Thread B acquiring the lock. Now if we interrupt Thread A, would control be transferred immediately to Thread A ? in which case, since the try catch block handling the InterrupException is within the synchronized context, and since only one Thread can hold the monitor at a time, what will happen to Thread B ? should it move to a blocked state until Thread A has finished execution ?
Thanks in Advance
Reading the documentation does in fact help:
http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Object.html#wait%28long%29
Thus, when the thread is interrupted, it has to re-acquire the Object's monitor to restore the synchronisation state before the exception is thrown. The same holds for returning from the wait(long) call after the specified amount of time has elapsed.
The thread T is then removed from the wait set for this object and
re-enabled for thread scheduling. It then competes in the usual manner
with other threads for the right to synchronize on the object; once it
has gained control of the object, all its synchronization claims on
the object are restored to the status quo ante - that is, to the
situation as of the time that the wait method was invoked. Thread T
then returns from the invocation of the wait method. Thus, on return
from the wait method, the synchronization state of the object and of
thread T is exactly as it was when the wait method was invoked.
If the current thread is interrupted by another thread while it is
waiting, then an InterruptedException is thrown. This exception is not
thrown until the lock status of this object has been restored as
described above.
I believe that A will become runnable but will wait until it can acquire the lock before proceeding with the catch clause. It won't force B into a blocked state. The whole point of a synchronized block is that the thread holding the lock is guaranteed that no other thread can synchronize on the same lock until it gives up its lock; forcing B into a blocked state and letting A reacquire the lock would violate the very essence of synchronization.