The code use Java 8:
public class MustDeadLock {
private static final Object obj1 = new Object();
private static final Object obj2 = new Object();
public static void main(String[] args) {
mockDeadLock();
}
public static void mockDeadLock() {
CompletableFuture cf1 = CompletableFuture.runAsync(() -> {
synchronized (obj1) {
System.out.println("thread A got lock: obj1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("thread A ready to get the rest lock");
synchronized (obj2) {
System.out.println("thread A got all locks");
}
}
});
CompletableFuture cf2 = CompletableFuture.runAsync(() -> {
synchronized (obj2) {
System.out.println("thread B got lock: obj2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("thread B ready to get the rest lock");
synchronized (obj1) {
System.out.println("thread B got all locks");
}
}
});
CompletableFuture.allOf(cf1, cf2);
System.out.println("program ready to terminate");
}
}
I'm wondering why
System.out.println("thread A ready to get the rest lock");
and
System.out.println("thread B ready to get the rest lock");)
don't get executed.
Why does it just print:
thread B got lock: obj2
thread A got lock: obj1
program ready to terminate
and then terminate the program rather than blocking?
Simply because your main thread continues the execution while the other threads are sleeping.
If you want to wait for these threads to complete before continuing the execution, you can for example join them before the end of the method:
// rest of the program
cf1.join();
cf2.join();
System.out.println("program ready to terminate");
This will print:
thread B got lock: obj2
thread A got lock: obj1
thread B ready to get the rest lock
thread A ready to get the rest lock
This will produce the deadlock and the program will never terminate.
Related
I am new to Java multithreading. I created simple producer-consumer pattern using wait and notify but my producer is getting called only once in tbe starting.
public class ThreadApp {
public static void main(String[] args) throws InterruptedException {
ProducerConsumerWorldp = new ProducerConsumerWorld();
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
try {
p.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
try {
p.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
class ProducerConsumerWorld{
public void producer() throws InterruptedException{
synchronized (this) {
while(true){
System.out.println("Producer thread started running");
wait();
System.out.println("Resumed Producing");
}
}
}
public void consumer() throws InterruptedException{
synchronized (this) {
while(true){
Thread.sleep(2000);
System.out.println("Consumer thread started running");
System.out.println("Press enter to consume all and start producing");
Scanner s = new Scanner(System.in);
s.nextLine();
notify();
Thread.sleep(2000);
System.out.println("consumed all");
}
}
}
}
I am creating separate threads for producer and consumer. Producer thread only gets called in the starting and then after it is never getting executed.
I tried two option to overcome this issue. first I put while condition outside of synchronized block second is given below.
class ProducerConsumerWorld{
public void producer() throws InterruptedException{
synchronized (this) {
while(true){
System.out.println("Producer thread started running");
notify();
wait();
System.out.println("Resumed Producing");
}
}
}
public void consumer() throws InterruptedException{
synchronized (this) {
while(true){
Thread.sleep(2000);
System.out.println("Consumer thread started running");
System.out.println("Press enter to consume all and start producing");
Scanner s = new Scanner(System.in);
s.nextLine();
notify();
Thread.sleep(2000);
System.out.println("consumed all");
wait();
}
}
}
}
Both works great. Which one the of the appropriate solution to use ? I am still unable to figure out why the code I put in question is not working properly.
I am still unable to figure out why the code I put in question is not working properly
The wait() in producer() releases the monitor which allows consumer() to enter its synchronized block. Then the wait() in producer() starts waiting till consumer() calls notify() and releases the monitor (i.e. exits its synchronized block). You never exit synchronized in consumer() therefore the wait() in producer() is blocked forever
I am still unable to figure out why the code I put in question is not
working properly
I've managed to fix your code, and I've attached below the fixed code snippet.
I've introduced a boolean instance variable named isConsumed for the ProducerConsumerWorld. In doing so, what essentially happens is that after Producer Thread produces, he updates the state of isConsumed to false, since he has produced something which is yet to be consumed. Afterwards, the producer notifies the the Consumer thread, that Producer has finished producing. Next, it invokes wait() on the ProducerConsumerWorld which releases Producer's lock on ProducerConsumerWorld. Then, it waits for the lock on ProducerConsumerWorld.
Meanwhile, the Consumer Thead acquires the lock on ProducerConsumerWorld, which allows it to enter the consumer method, where it checks if there is produce yet to be consumed. If so, it consumes and updates the isConsumed variable to true, and notifies the produce has been consumed. Then the consumer proceeds to releases its lock on ProducerConsumerWorld by calling wait(), and waits to reacquire the lock on ProducerConsumerWorld after Producer has consumed.
Note:
Calling notify() doesn't release a lock until the thread moves out of the synchronized block, or wait() is called, thus releasing the lock.
Source: Oracle's OCA/OCP Java SE 7 Study Guide Page 760
Code:
import java.util.Scanner;
public class ThreadApp {
public static void main(String[] args) throws InterruptedException {
ProducerConsumerWorld p = new ProducerConsumerWorld();
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
try {
p.producer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
#Override
public void run() {
try {
p.consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
class ProducerConsumerWorld{
boolean consumed = false;
public void producer() throws InterruptedException{
System.out.println("Producer thread started running");
synchronized (this) {
while(this.consumed == true){ // Consumer has consumed and is waiting for produce
System.out.println("Resumed Producing");
this.consumed = false;
notify();
wait();
}
}
}
public void consumer() throws InterruptedException{
synchronized (this) {
while(this.consumed == false){
Thread.sleep(2000);
System.out.println("Consumer thread started running");
System.out.println("Press enter to consume all and start producing");
Scanner s = new Scanner(System.in);
s.nextLine();
this.consumed = true;
System.out.println("consumed all");
notify();
wait();
}
}
}
}
This gives me an output like,
I am learning threading in java. As per the description of finally block in an Oracle tutorial:
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
So I tried to interrupt a thread in try catch block and check whether finally is executed in following class. But as per the output of the program, finally block is executed. Can someone explain what happened?
package com.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock{
public static void main(String[] args) throws InterruptedException {
MyThread lockT= new MyThread();
Thread t= new Thread(lockT);
t.setName("TempThread1");
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
class MyThread implements Runnable {
Lock lock;
public MyThread() {
lock= new ReentrantLock();
}
#Override
public void run() {
try {
if(lock.tryLock()){
Thread.sleep(5000);
while (!Thread.currentThread().isInterrupted()) {
System.out.println("My thread name is "+ Thread.currentThread().getName());
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
System.out.println("finally ");
lock.unlock();
}
}
}
The rule here is saying: may not execute which does not mean it will not execute.
So basically the rule is saying: don't rely that the finally block will be executed, we don't provide such guarantees.
I know it's a old thread but I'd like to present a situation where the threads get interrupted and doesn't execute finally: Here is the sample code:
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.LockWork();
}public void LockWork() {
WithLock withLock = new WithLock();
Thread t1 = new Thread(() -> {
withLock.produce();
});
Thread t2 = new Thread(() -> {
withLock.consume();
});
ExecutorService service= Executors.newCachedThreadPool(new WithLockThreadFactory());
Future f1=service.submit(t1);
Future f2=service.submit(t2);
//f1.cancel(true);
try {
System.out.println("-------------------------------------sleeping now-------------------------------------");
Thread.sleep(3000);
System.out.println("-------------------------------------Intereputing Producer-------------------------------------");
f1.cancel(true);
service.shutdown();
Thread.sleep(1000);
System.out.println("is Producer done: "+f1.isDone());
service.awaitTermination(1, TimeUnit.DAYS);
System.out.println("is Consumer done: "+f2.isDone());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Ending Program");
}
now There is my Thread Factory:
public class WithLockThreadFactory implements ThreadFactory {
private int counter;
public WithLockThreadFactory() {
this.counter = 1;
}
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "WithLockThreadFactoryThread " + counter);
counter++;
return t;
}
now WithLock Class:
public class WithLock {
ReentrantLock lock = new ReentrantLock(true);
LinkedList<Integer> linkedList = new LinkedList<>();
Condition isEmpty = lock.newCondition();
Condition isFull = lock.newCondition();
int limit = 10;
volatile int interruptCounter = 0;
public void produce() {
System.out.println("WithLock.produce() Name: " + Thread.currentThread().getName());
try {
int value = 1;
while (true) {
lock.lockInterruptibly();
if (limit == linkedList.size()) {
System.out.println("acquiring lock in produce");
isEmpty.await(3000, TimeUnit.MILLISECONDS);
}
linkedList.add(value % limit);
System.out.println("value added to list: " + value % limit);
value++;
isFull.signal();
System.out.println("notifiedy lock in produce");
lock.unlock();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("I was interupted Producer");
interruptCounter++;
System.out.println("interruptCounter value :" + interruptCounter);
} finally {
lock.unlock();
System.out.println("Finally Unlocked Producuer");
}
System.out.println("Ending things now: Producer");
}
public void consume() {
System.out.println("WithLock.consume() Name: " + Thread.currentThread().getName());
try {
while (true) {
lock.lockInterruptibly();
// no use as poll doesn't throw an exception if the queue is
// empty
if (linkedList.size() == 0) {
System.out.println("acquiring lock in consume");
isFull.await(3000, TimeUnit.MILLISECONDS);
if (interruptCounter > 2) {
break;
}
}
System.out.println("removing element from queue: " + linkedList.poll());
isEmpty.signal();
System.out.println("notifiedy lock in consume");
lock.unlock();
Thread.sleep(1000);
if (interruptCounter != 0) {
interruptCounter++;
}
}
} catch (InterruptedException e) {
System.out.println("I was Interupted Consumer");
} finally {
lock.unlock();
System.out.println("Finally Unlocked Consumer");
}
System.out.println("Ending things now: Consume");
}
}
and this is the output in the console:
-------------------------------------sleeping now-------------------------------------
WithLock.produce() Name: WithLockThreadFactoryThread 1
WithLock.consume() Name: WithLockThreadFactoryThread 2
value added to list: 1
notifiedy lock in produce
removing element from queue: 1
notifiedy lock in consume
acquiring lock in consume
value added to list: 2
notifiedy lock in produce
removing element from queue: 2
notifiedy lock in consume
acquiring lock in consume
value added to list: 3
notifiedy lock in produce
removing element from queue: 3
notifiedy lock in consume
-------------------------------------Intereputing Producer-------------------------------------
I was interupted Producer
interruptCounter value :1
acquiring lock in consume
is Producer done: true
removing element from queue: null
notifiedy lock in consume
acquiring lock in consume
Finally Unlocked Consumer
Ending things now: Consume
is Consumer done: true
Ending Program
This is something I found interesting and wanted to share. I tried it in JAVA8.
If the JVM exits...
Try System.exit() call...
First and foremost, Oracle's tutorials are descriptive and not normative. Your quote should by no means be taken as specification of behavior.
The thread can be interrupted while executing the finally block, in which case the said finally block may indeed fail to complete. This is, however, fully under your control and you can always write such a finally which is not susceptible to this happening.
Rest assured that the finally block will not be skipped over due to a regular InterruptedException occurring within its try block.
If a thread is being repeatedly stop()ped, however, it will be harder to ensure the finally block executes.
I am trying to understand the use of Synchronized block.
In the below program, Inside a produce and consumer method I have created a synchronized block and if I lock it by using lock1(object). I am getting the following error, why is this, why am i getting this error?
I am aware that by replacing lock1 by this(same class). I can get rid of the error. I still want to know why this error as everything seems very logical to me.
Program
import java.util.Scanner;
public class Worker {
private Object lock1 = new Object();
private Object lock2 = new Object();
public void produce() throws InterruptedException {
synchronized (lock1) {
System.out.println("Producer thread running");
wait();
System.out.println("Producer resumed");
}
}
public void consumer() throws InterruptedException {
Scanner scanner = new Scanner(System.in);
Thread.sleep(2000);
synchronized (lock1) {
System.out.println("Waiting for return key");
scanner.nextLine();
System.out.println("return key is pressed");
notify();
Thread.sleep(5000);
System.out.println("Consumer is over");
}
}
public void main() {
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
consumer();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at Worker.produce(Worker.java:14)
at Worker$1.run(Worker.java:43)
at java.lang.Thread.run(Unknown Source)
synchronized (lock1) {
System.out.println("Producer thread running");
wait();
System.out.println("Producer resumed");
}
You acquire the monitor of lock1 and then proceed to wait on this which fails because, as the documentation of Object#wait states,
The current thread must own this object's monitor.
You need to call lock1.wait() and lock1.notify(). You can only call wait() or notify() on an object on which you hold the lock (lock1 in this case).
In the synchronized block the current thread is the owner of the synchronization object's monitor.
In your case it is lock1.
According to the javadoc of Object.wait()
The current thread must own this object's monitor.
and Object.notify()
This method should only be called by a thread that is the owner of this object's monitor.
you must change your code to
synchronized (lock1) {
System.out.println("Producer thread running");
lock1.wait();
System.out.println("Producer resumed");
}
and
synchronized (lock1) {
System.out.println("Waiting for return key");
scanner.nextLine();
System.out.println("return key is pressed");
lock1.notify();
Thread.sleep(5000);
System.out.println("Consumer is over");
}
To call wait() and notify() you need to own the object's monitor you want to call these two methods.
Link to javadoc Object.wait()
Citation from above link:
The current thread must own this object's monitor.
I am showing how I fixed the producer-consumer problem.
I have using different way then you. I think this will help you..
And the to make any block or method synchronized their are some condition :
synchronized methods prevent more than one thread from accessing an
object's critical method code simultaneously.
You can use the synchronized keyword as a method modifier, or to start a
synchronized block of code.
To synchronize a block of code (in other words, a scope smaller than the
whole method), you must specify an argument that is the object whose lock
you want to synchronize on.
While only one thread can be accessing synchronized code of a particular
instance, multiple threads can still access the same object's unsynchronized code.
static methods can be synchronized, using the lock from the
java.lang.Class instance representing that class.
All three methods—wait(), notify(), and notifyAll()—must be
called from within a synchronized context! A thread invokes wait() or
notify() on a particular object, and the thread must currently hold the lock
on that object.
class P implements Runnable{
Data d;
P(Data d){
this.d = d;
new Thread(this,"Producer").start();
}
public void run(){
for(int i=0; i<=20; i++){
d.set(i);
System.out.println("put -> "+i);
}
}
}
class C implements Runnable{
Data d;
C(Data d){
this.d = d;
new Thread(this,"Consumer").start();
}
public void run(){
for(int i=0; i<=20; i++){
int n = d.get();
System.out.println("get -> "+n);
}
}
}
class Data{
int n;
boolean valueset=false;
synchronized void set(int n){
if(valueset){
try{
wait();
}catch(Exception e){
System.out.println("set -> Exception "+e);
}
}
this.n = n ;
valueset=true;
notify();
}
synchronized int get(){
if(!valueset){
try{
wait();
}catch(Exception e){
System.out.println("get -> Exception "+e);
}
}
valueset=false;
notify();
return n ;
}
}
class PC{
public static void main(String[] args){
Data d = new Data();
new P(d);
new C(d);
}
}
You can download solution of producer consumer from here :
https://www.mediafire.com/?52sa1k26udpxveu
I wanted to verify in my own eyes the different between sleep and wait.
Wait can only be done in a synchronized block because it releases the ownership of the monitor lock.
While sleep is not related to the monitor lock and a thread that is already the owner of the monitor lock shouldn't lose its ownership if sleeping.
For that i made a test:
Steps:
Started a thread that waits in a synched block for 5 secs.
Waited 3 secs and started another thread that acquires the monitor lock (because Thread-A is waiting) and simply sleeps for 5 secs while holding the monitor lock.
Expected result:
Thread - A will only re-acquire the lock after 8 seconds, When Thread - B finally releases the monitor lock by exiting the synch block.
Actual result.
Thread - A acquires the monitor lock after 5 seconds.
Can some1 explain to me what happened here?
public static void main(String[] args) {
Runnable r1 = new Runnable() {
#Override
public void run() {
System.out.println("r1 before synch block");
synchronized (this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
#Override
public void run() {
System.out.println("r2 before synch block");
synchronized (this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
EDIT:
Ok I understand my error - I waiting on this - r1/r2 and not on the same object.
Now I changed it and both acquire on the same object - The class instance of Main.
1. r1 acquires ownership of the monitor lock of Main.this
2. r1 Releases it.
3. When r1 tries to re-acquire it I get an exception:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at Main$1.run(Main.java:28)
at java.lang.Thread.run(Unknown Source)
on synchronized (Main.this)
What is the problem here?
public static void main(String[] args) {
Main main = new Main();
main.test();
}
public void test() {
Runnable r1 = new Runnable() {
#Override
public void run() {
System.out.println("r1 before synch block");
synchronized (Main.this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
#Override
public void run() {
System.out.println("r2 before synch block");
synchronized (Main.this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
The two threads actually hold two different locks. Say your class name is MyClass, change two lines of synchronized (this) to synchronized (MyClass.this), that makes the two threads to hold same lock.
here's a much better way to make the test work , and show that it works .
your problem was that you didn't wait correctly and used Thread.currentThread() for no reason .
btw, in case you want to use signalling of the wait-notifier mechanism without losing the signal , i suggest you read this link.
public class MAIN
{
public static void main(final String[] args)
{
final Object sync =new Object();
final long startTime=System.currentTimeMillis();
final Runnable r1=new Runnable()
{
#Override
public void run()
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 before synch block");
synchronized(sync)
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 entered synch block");
try
{
sync.wait(5000);
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 finished waiting");
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println((System.currentTimeMillis()-startTime)/1000+": r1 exited synch block");
}
};
final Runnable r2=new Runnable()
{
#Override
public void run()
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 before synch block");
synchronized(sync)
{
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 entered synch block");
try
{
Thread.sleep(5000);
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 finished waiting");
}
catch(final InterruptedException e)
{
e.printStackTrace();
}
}
System.out.println((System.currentTimeMillis()-startTime)/1000+": r2 exited synch block");
}
};
try
{
final Thread t1=new Thread(r1);
final Thread t2=new Thread(r2);
t1.start();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println((System.currentTimeMillis()-startTime)/1000+": Finished joining");
}
catch(final Exception e)
{
e.printStackTrace();
}
}
}
public class Main2 {
public static void main(String[] args) {
new Test2().start();
new Test2().start();
}
}
class Test2 extends Thread {
#Override
synchronized public void run() {
try {
System.out.println("begin wait");
wait();
} catch (Exception ex) {
}
}
}
As the actual result of running the test:
begin wait,
begin wait,
two times from the two threads.
Contrast to the expected result:
begin wait,
only one time from one of the two threads because wait() is called inside the synchronized run() method.
Why could call to Object's wait() break thread synchronization?
Thans a lot!
public class Main3 {
public static void main(String[] args) {
Test3 t = new Test3();
new Thread(t).start();
new Thread(t).start();
}
}
class Test3 implements Runnable {
synchronized public void run() {
try {
System.out.println("begin wait");
wait();
} catch (Exception ex) {
}
}
}
#akf & #Sean Owen
Thanks for your replies. Sorry for my mistake, now i modified the code to place the synchronization on the same object's run(), the result remained: begin wait, begin wait, two times.
#akf
wait will release the lock that
synchronize has grabbed, and will be
re-gotten once the thread is notified.
Could you elaborate a little bit?
The object that you are synchronizing on in this example is not the class, but the instance, so each new Test2 object would be synchronizing on a different monitor.
The method you might be looking for here is sleep, not wait. wait will release the lock that synchronized has grabbed, and will be re-gotten once the thread is notified.
Note that for your test to work correctly, you will need to lock on a common object. If you want to see wait in action, I have thrown together a simple app that will pop up a frame with a "Notify" button. Two threads will be started that wait on a common object and are in turn notified when the button is pressed.
public static void main(String[] args)
{
final Object lock = new Object();
final JFrame frame = new JFrame("Notify Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Notify");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
synchronized(lock) {
lock.notify();
}
}
});
frame.add(button);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible( true );
}
});
new Thread(new Runnable() {
public void run() {
synchronized(lock) {
try {
System.out.println("1. starting");
lock.wait();
System.out.println("1. step 1");
lock.wait();
System.out.println("1. step 2");
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
synchronized(lock) {
try {
System.out.println("2. starting");
lock.wait();
System.out.println("2. step 1");
lock.wait();
System.out.println("2. step 2");
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}).start();
}
For a simple explanation of wait, the JavaDoc is always a good place to start:
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).
The current thread must own this object's monitor. 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.
You have two different Test2 objects. Synchronized methods lock on the object. They are not acquiring the same lock, so no it should print twice.
an simple example that can help you is this:
public class test {
public static void main(String[] args) {
Prova a=new Prova();
new Test2(a).start();
new Test2(a).start();
}
}
class Prova{
private boolean condition;
public void f(){
while(condition){
//Thread.currentThread Returns a reference to the currently executing thread object.
//Thread.getName() return name Thread
System.out.println(Thread.currentThread().getName()+" begin wait");
try{
wait();
}catch(InterruptedException c){return;}
}
System.out.println(Thread.currentThread().getName()+" first to take the mutex");
condition=true;
}
}
class Test2 extends Thread {
private Prova a;
private static boolean condition;
public Test2(Prova a){
this.a=a;
}
#Override
public void run() {
synchronized(a){
try {
a.f();
} catch (Exception ex) {
}
}
}
}
in this case the two threads synchronize an object, the first taking the lock release message, the second one waits. in this example uses the condition variable
summary to wait/notify mechanism:
1)current thread reaches one object's synchronized code block which contains the call to wait(), it competes with other threads for the lock(the object's monitor), as winner it executes the block till the call to wait() encounters.
2)by calling wait(), current thread releases the lock to other competing threads, then halts execution, wait for notify being sent from another thread who succeeds in obtaining the lock.
JavaDoc:
A thread becomes the owner of
the object's monitor in one of three
ways:
•By executing a synchronized instance
method of that object.
•By executing
the body of a synchronized statement
that synchronizes on the object.
•For
objects of type Class, by executing a
synchronized static method of that
class.
3)another thread reaches the same object's yet another synchronized code block which contains the call to notify/notifyAll(), it competes with other threads for the lock, as winner it executes the block till finishing the call to notify/notifyAll(). It will release the lock either by call to wait() or at the end of the execution on the block.
4)upon receiving notify/notifyAll(), current thread competes for the lock, as winner the execution continues where it has halted.
simple example:
public class Main3 {
public static void main(String[] args) {
Test3 t = new Test3();
new Thread(t).start();
new Thread(t).start();
try {
Thread.sleep(1000);
} catch (Exception ex) {
}
t.testNotifyAll();
}
}
class Test3 implements Runnable {
synchronized public void run() {
System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock");
try {
wait();
} catch (Exception ex) {
}
System.out.println(Thread.currentThread().getName() + ": " + "wait block got the lock again");
try {
Thread.sleep(1000);
} catch (Exception ex) {
}
System.out.println(Thread.currentThread().getName() + ": " + "bye wait block");
}
synchronized void testNotifyAll() {
System.out.println(Thread.currentThread().getName() + ": " + "notify block got the lock");
notifyAll();
System.out.println(Thread.currentThread().getName() + ": " + "notify sent");
try {
Thread.sleep(2000);
} catch (Exception ex) {
}
System.out.println(Thread.currentThread().getName() + ": " + "bye notify block");
}
}
output:
Thread-0(or 1): wait block got the
lock
Thread-1(or 0): wait block got
the lock
main: notify block got the
lock
main: notify sent
main: bye notify block
Thread-0(or 1): wait block
got the lock again
Thread-0(or 1): bye
wait block
Thread-1(or 0): wait block
got the lock again
Thread-1(or 0): bye
wait block