How can two threads access a synchronized block simultaneously? That is, how can I make one thread give the chance for the other thread to execute a synchronized block, even before this thread finishes the execution of the same synchronized block?
See wait(), notify(), and notifyAll().
Edit: The edit to your question is incorrect. The sleep() method does not release the monitor.
For example:
private static final Object lock = new Object();
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.execute(new One());
executorService.execute(new Two());
}
static class One implements Runnable {
#Override
public void run() {
synchronized (lock) {
System.out.println("(One) I own the lock");
System.out.println("(One) Giving up the lock and waiting");
try {
lock.wait();
} catch (InterruptedException e) {
System.err.println("(One) I shouldn't have been interrupted");
}
System.out.println("(One) I have the lock back now");
}
}
}
static class Two implements Runnable {
#Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
System.err.println("(Two) I shouldn't have been interrupted");
}
synchronized (lock) {
System.out.println("(Two) Now I own the lock (Two)");
System.out.println("(Two) Giving up the lock using notify()");
lock.notify();
}
}
}
It sounds like you might want to consider using more than one synchronized block, particularly if there's a blocking operation that one thread is getting caught on and thus blocking another thread that wants to execute something else in the block.
A synchronized block is a block of code which can (by definition) only be accessed by one thread at a time.
Saying that you want another thread to enter this block while another thread also currently processes it, does make the synchronized block scheme useless.
You probably want to split the synchronized block into many other ones.
The only way I can see if one thread calls wait() on monitor object. Then it will release monitor and wait for notification while other thread can execute synchronized block. Then other thread will have to call notify()/notifyAll() so first thread gets monitor back and continue.
A thread can release its monitor using lock.wait(). Another thread can then pick up the monitor and enter the synchronized block.
Example:
public class MultipleThreadsInSynchronizedBlock {
public static void main(String... args) {
final Object lock = new Object();
Runnable runnable = new Runnable() {
public void run() {
synchronized (lock) {
System.out.println("Before wait");
try {
lock.wait();
} catch (InterruptedException e) {
}
System.out.println("After wait");
}
}
};
new Thread(runnable).start();
new Thread(runnable).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
synchronized (lock) {
lock.notifyAll();
}
}
}
This prints:
Before wait
Before wait
After wait
After wait
However it's not a "hack" to allow a mutually exclusive block to be run non-atomically. If you're going to use very low-level synchronization primitives like this you need to know what you're doing.
Related
I'm having a hard time understanding synchronized. Since the first thread doesn't do anything with the object 2, doesn't it "unlock" everything in a second?
public class Uninterruptible {
public static void main(String[] args) throws InterruptedException {
final Object o1 = new Object(); final Object o2 = new Object();
Thread t1 = new Thread() {
public void run() {
try {
synchronized(o1) {
Thread.sleep(1000);
synchronized(o2) {}
}
} catch(InterruptedException e) { System.out.println("t1 interrupted"); }
}
};
Thread t2 = new Thread() {
public void run() {
try {
synchronized(o2) {
Thread.sleep(1000);
synchronized(o1) {}
}
} catch(InterruptedException e) { System.out.println("t2 interrupted"); }
}
};
t1.start(); t2.start();
Thread.sleep(2000);
t1.interrupt(); t2.interrupt();
t1.join(); t2.join();
System.out.println("Donezo!");
}
}
It doesn't matter that the inner synchronized blocks do nothing. Java will still attempt to acquire the lock on the the object specified.
No matter whether you have nothing or a huge amount of processing in the inner synchronized blocks, what you have is the minimal example to create a deadlock: two different threads, each owning the lock on a distinct resource, each attempting to acquire the lock on each other's resource.
The deadlock occurs before either thread even gets to executing the inner synchronized block, because neither thread can get locks on both resources at the same time.
The code winds up doing nothing but hanging, with each thread blocked. Your calls to interrupt are too late to cause an InterruptedException; they only set the "interrupted status" in the Thread. Commenting out Thread.sleep(2000) will let the calls to interrupt catch the Threads while they are still sleeping, before they even attempt to acquire the second lock.
This program works fine by printing alternate numbers via different threads but when all the numbers from 0-9 are printed Why does this program not stop? I have to manually stop my application.
public class EvenOddPrinter implements Runnable{
private AtomicInteger num = new AtomicInteger(0);
private Object lock = new Object();
#Override
public void run() {
synchronized (lock){
while (num.get()<10){
System.out.println(num.getAndAdd(1) + " - "+Thread.currentThread().getName());
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Executor {
public static void main(String[] args) throws InterruptedException {
EvenOddPrinter eop = new EvenOddPrinter();
Thread t1 = new Thread(eop);
Thread t2 = new Thread(eop);
t1.start();
t2.start();
}
}
that's because in the last Thread getting stuck at wait. notifyAll will notify all waiting thread if any there and release lock.
while (num.get()<10){
// existing implementation
}
lock.notifyAll();
The second thread t2 keeps waiting on the lock in the end, and t1 doesnt do the notify() anymore because the while condition becomes false. You must put a lock.notify(); statement outside of the while loop.
As soon as the number reached 8 the first thread calls notify() and goes to wait(). Second thread then makes the number 9 and calls notify() and goes to wait(). First thread is then not able to go inside the loop as specified in the condition, therefore, it exits the synchronized and block and finishes but second thread is still waiting. There has to be a mechanism to notifyAll() as soon as one of the threads exits the synchronized block which is exactly what I did.
#Override
public void run() {
synchronized (lock){
while (num.get()<10){
System.out.println(num.getAndAdd(1) + " - "+Thread.currentThread().getName());
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.notifyAll();
}
Also, lock is pointless when I am using AtomicInteger (or the other way round).
I'm trying to check how wait/notify works in java.
Code:
public class Tester {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
synchronized (t) {
try {
System.out.println("wating for t to complete");
t.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (this) {
System.out.println("entering syncronised block");
notify();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
Output Returned
wating for t to complete
entering run method
entering syncronised block
//sleep called
leaving syncronized block
leaving run method
wait over
I was expecting when notify() is executed the wait will be over & System.out.println("wait over"); will get printed. But it seems it only gets printed when t finished its run().
Object monitor locks need to be performed a single reference of the same lock...
In your example you are waiting on an instance of the Thread, but using notify from the Runnable. Instead, you should use a single, common lock object...for example
public class Tester {
public static final Object LOCK = new Object();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
synchronized (LOCK) {
try {
System.out.println("wating for t to complete");
LOCK.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (LOCK) {
System.out.println("entering syncronised block");
LOCK.notify();
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
}
Output...
wating for t to complete
entering run method
entering syncronised block
leaving syncronized block
wait over
leaving run method
wait over and leaving run method could change positions depending on the thread scheduling.
You could try putting the sleep out side the synchronized block. This will release the monitor lock allowing the wait section to continue running (as it can't start until the lock is released)
public static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (LOCK) {
System.out.println("entering syncronised block");
LOCK.notify();
System.out.println("leaving syncronized block");
}
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("leaving run method");
}
}
Answer to updated code :
From Thread.sleep() javadoc:
Causes the currently executing thread to sleep (temporarily cease execution) for the
specified number of milliseconds, subject to the precision and accuracy of system timers
and schedulers. The thread does not lose ownership of any monitors.
If you call Thread.sleep while inside a synchronized block, other threads won't be able to enter the synchronized block. You should never do time consuming tasks while in a synchronized block to avoid this.
Note (as others pointed out as well) that you have to use the same object for locking/synchronizing in both threads.
If you want your main thread to continue immediately after notify is called, you have to relinquish the lock temporarily. Otherwise wait will get called only after the secondary thread leaves the synchronized block. And it's never a good idea to keep a lock in a long running computation!
One way how to achieve is to use wait(int) on the lock instead of sleep, because wait releases the synchronization lock temporarily:
public class Tester {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
synchronized (lock) {
try {
System.out.println("wating for t to complete");
lock.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (lock) {
System.out.println("entering syncronised block");
lock.notify();
try {
lock.wait(1000); // relinquish the lock temporarily
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
}
However, using these low-level primitives can be very error prone and I'd discourage from using them. Instead, I'd suggest you to use Java's high-level primitives for that. For example, you can use CountDownLatch which lets one thread wait until other threads count down to zero:
import java.util.concurrent.*;
public class TesterC {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
System.out.println("wating for t to complete");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait over");
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
try {
latch.countDown();
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving run method");
}
}
}
Here you don't have to synchronize anything, the latch does everything for you. There are many other primitives you can use - semaphores, an exchanger, thread-safe queues, etc. Explorer the java.util.concurrent package.
Perhaps even better solution is to use even higher level API, such as Akka provides. There you work with Actors or Software transactional memory, which can be composed easily and spare you of most of concurrency issues.
I don't see how the following code produces output that appears to contravene the definition of an object lock. Surely only one thread should be allowed to print the "acquired lock" message yet they both do?
class InterruptThreadGroup {
public static void main(String[] args) {
Object lock = new Object();
MyThread mt1 = new MyThread(lock);
MyThread mt2 = new MyThread(lock);
mt1.setName("A");
mt1.start();
mt2.setName("B");
mt2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
// Thread.currentThread().getThreadGroup().interrupt();
}
}
class MyThread extends Thread {
private Object lock;
public MyThread(Object l) {
this.lock = l;
}
public void run() {
synchronized (lock) {
System.out.println(getName() + " acquired lock");
try {
lock.wait();
} catch (InterruptedException e) {
System.out.println(getName() + " interrupted.");
}
System.out.println(getName() + " terminating.");
}
}
}
It is because the call to lock.wait() releases the lock, allowing the second thread to enter the synchronized block. Extract from the javadoc
The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
Note that there are a few issues in your code such as:
you should not wait outside of a while loop
there is no notify anywhere so your wait could last forever
it is a better practice to have your task implement Runnable and pass it as an argument to a Thread's constructor than to extend Thread directly.
Either you should use synchronized block or wait call . using them together will not work. if you use wait call then the lock is released by the object in synchronized block.
So remove the line lock.wait and your programme will work as you want. synchronize block will handle all lock automatically.
if you are using wait then must use notify.
Here is good thread about this: Why must wait() always be in synchronized block
can not reproduce deadlock using the next code
I am trying yo get a deadlock using the next code,
but it seems that it works good.
Please see below:
public class Deadlock {
static Object lock1 = new Object();
static Object lock2 = new Object();
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized (lock1) {
System.out.println("Thread 1: locked lock1");
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1: locked lock2");
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized (lock2) {
System.out.println("Thread 2: locked lock2");
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2: locked lock1");
}
}
}
}).start();
}
}
What I don't understand in this case or what's wrong in this code?
To cause a deadlock, you need to hold both locks in these threads in reverse order.
// thread 1
public void run() {
synchronized (lock1) {
synchronized (lock2) {
// do something
}
}
}
// thread 2
public void run() {
synchronized (lock2) {
synchronized (lock1) {
// do something
}
}
}
This is necessary, but not sufficient. To be able to simulate the deadlock, you need to make sure both threads acquire their first locks respectively successfully before attempting to acquire the next.
Why would the above code cause a deadlock? Each thread only locks one lock at a time, so if the other thread tries to lock it, it just has to wait for the first one to release it.
You would have a serious risk of deadlock if the threads did
synchronized (lock1) {
synchronized (lock2) {
...
}
}
and
synchronized (lock2) {
synchronized (lock1) {
...
}
}
Your code will never "dead lock".
To dead lock, you must lock the other lock within a lock.
To get a deadlock you need to hold two locks at once. You can hold the first lock for the whole loop.
If you are trying to get a deadlock, you need to nest the synchronized blocks so that you attempt to whole both locks simultaneously:
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized (lock1) {
System.out.println("Thread 1: locked lock1");
try {
// Sleep to allow Thread2 to obtain lock2
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1: locked lock2");
}
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
// Sleep to allow Thread1 to obtain lock1
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 2: locked lock2");
synchronized (lock1) {
System.out.println("Thread 2: locked lock1");
}
}
}
}
}).start();
Note that the locks are acquired in reverse order, with sleeps to ensure the following acquisition order:
Thread 1 acquires lock1
Thread 2 acquires lock2
Thread 1 attempts to acquire lock2 <--- DEADLOCK
Thread 2 attempts to acquire lock1 <--- DEADLOCK
Note that the last two can happen in either order, but the deadlock will occur regardless.
Have the second thread try to get a lock on lock1. That's the classic way to invoke deadlock. Two resources locked in different orders.
Sorry... didn't scroll down far enough in your code... feeling foolish