File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Threads and Synchronization and the fly likes Beginner: Threads vs. Runnables Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Threads and Synchronization
Bookmark "Beginner: Threads vs. Runnables" Watch "Beginner: Threads vs. Runnables" New topic
Author

Beginner: Threads vs. Runnables

Randy Gibbons
Greenhorn

Joined: Feb 06, 2005
Posts: 14
I'm doing my first concurrency exercices. I can't figure out why the following works when my objects subclass Thread but don't when they implement Runnable:

Works:



Doesn't work (seems that notify() never "gets through"):

Henry Wong
author
Sheriff

Joined: Sep 28, 2004
Posts: 19070
    
  40

In your example, when you inherit from the Thread class, both threads use the *same* object for notifications -- the thread object of the waiter.

In your example, when you use runnables, the two threads are *not* using the same object. The notify thread is using the wait thread object, while the wait thread is using the runnable object embedded in the wait thread object.

Henry


Books: Java Threads, 3rd Edition, Jini in a Nutshell, and Java Gems (contributor)
Randy Gibbons
Greenhorn

Joined: Feb 06, 2005
Posts: 14
I see the light, thanks. In my greenhornness, I wasn't distinguishing between the thread object itself and the potentially different Runnable object containing the thread's task.
A mild criticism of Eckel's chapter on Concurrency (Thinking in Java, 3rd Edition), which is my introduction to the topic: Since he has an expressed preference for subclassing Thread rather than using Runnable (since, where appropriate, the Thread subclass can be an inner class and therefore not prevent the outer class from inheriting from something else), he doesn't have many examples using Runnable. Seems to me my confusion would be common among beginners and should be addressed in an introductory text (nevertheless, I find the Eckel book awesome).
I'm off to Borders this afternoon to buy your 3rd edition on Threads.
For those following this "thread," here is a version of "Runnables" that works:
Alan Mehio
Ranch Hand

Joined: Apr 04, 2005
Posts: 73
Please correct me if I am wrong but I executed your code after I inserted
some flag messages and I have noticed the execution passes the notify in both casess so there is no difference if we extend Thread or if we implement Runnable.
please take a look at the code (Eclipse 3.1 and Window 2000 J2SDK 1.4.2_07)

A- extends Thread


<result>
Waiter is holding the lock now inside the synchronized block
Waiter will wait
Notifier will sleep
Notifier waked up from a sleep
Notifier holding the lock before notify call
Notifier holding the lock after notify call
Waiter is back to run
Waiter IS NOT holding the lock now outside the synchronized block
Waiter is awakened
Waiter is holding the lock now inside the synchronized block
Waiter will wait
NotifierIS NOT holding the lock outside the synchronized block
Notifier will sleep
Notifier waked up from a sleep
Notifier holding the lock before notify call
Notifier holding the lock after notify call
Waiter is back to run
Waiter IS NOT holding the lock now outside the synchronized block
Waiter is awakened
Waiter is holding the lock now inside the synchronized block
...etc
</result>

<code>

class Waiter extends Thread {
Waiter(String name){
super(name);
}

public void run(){
while(true){
synchronized(this){
if (Thread.currentThread().holdsLock(this))
System.out.println(Thread.currentThread().getName() + " is holding the lock now inside the synchronized block");
try {
System.out.println(Thread.currentThread().getName() + " will wait");
wait();
System.out.println(Thread.currentThread().getName() + " is back to run");
}catch(InterruptedException ie){
throw new RuntimeException();
}
}
if (Thread.currentThread().holdsLock(this))
System.out.println(Thread.currentThread().getName() + " is holding the lock now outside the synchronized block");
else
System.out.println(Thread.currentThread().getName() + " IS NOT holding the lock now outside the synchronized block");

System.out.println(" Waiter is awakened");

}
}
}

class Notifier extends Thread {
private Thread ot;

Notifier(Thread otherThread, String name){
super(name);
ot = otherThread;
}

public void run(){
while(true){
try {
System.out.println(Thread.currentThread().getName() + " will sleep");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " waked up from a sleep");
} catch(InterruptedException ie) {
throw new RuntimeException();
}
synchronized(ot){
if (Thread.currentThread().holdsLock(ot))
System.out.println(Thread.currentThread().getName() + " holding the lock before notify call");
ot.notify();
if (Thread.currentThread().holdsLock(ot))
System.out.println(Thread.currentThread().getName() + " holding the lock after notify call");
else
System.out.println(Thread.currentThread().getName() + " IS NOT holding the lock after notify call");
}
if (Thread.currentThread().holdsLock(ot))
System.out.println(Thread.currentThread().getName() + " holding the lock outside the synchronized block");
else
System.out.println(Thread.currentThread().getName() + "IS NOT holding the lock outside the synchronized block");

}
}
}

public class Threads {

public static void main(String[] args) {
Thread t1 = new Waiter("Waiter");
Thread t2 = new Notifier(t1, "Notifier");
t1.start();
t2.start();
}
}

</code>


B- Runnable

<result>
Waiter is holding the lock now inside the synchronized block
Waiter will wait
Notifier will sleep
Notifier waked up from a sleep
Notifier holding the lock before notify call
Notifier holding the lock after notify call
Waiter is back to run
Waiter IS NOT holding the lock now outside the synchronized block
Waiter is awakened
Waiter is holding the lock now inside the synchronized block
Waiter will wait
NotifierIS NOT holding outside the synchronized block
Notifier will sleep
Notifier waked up from a sleep
Notifier holding the lock before notify call
Notifier holding the lock after notify call
Waiter is back to run
Waiter IS NOT holding the lock now outside the synchronized block
Waiter is awakened
Waiter is holding the lock now inside the synchronized block
Waiter will wait
NotifierIS NOT holding outside the synchronized block
Notifier will sleep

... etc

</result>

<code>
class Waiter implements Runnable {

public void run(){
while(true){
synchronized(this){
if (Thread.currentThread().holdsLock(this))
System.out.println(Thread.currentThread().getName() + " is holding the lock now inside the synchronized block");
try {
System.out.println(Thread.currentThread().getName() + " will wait");
wait();
System.out.println(Thread.currentThread().getName() + " is back to run");
}catch(InterruptedException ie){
throw new RuntimeException();
}
}
if (Thread.currentThread().holdsLock(this))
System.out.println(Thread.currentThread().getName() + " is holding the lock now outside the synchronized block");
else
System.out.println(Thread.currentThread().getName() + " IS NOT holding the lock now outside the synchronized block");

System.out.println(" Waiter is awakened");

}
}
}

class Notifier implements Runnable {
private Runnable waiter;

Notifier(Runnable waiter){

this.waiter = waiter;
}

public void run(){
while(true){
try {
System.out.println(Thread.currentThread().getName() + " will sleep");
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " waked up from a sleep");
} catch(InterruptedException ie) {
throw new RuntimeException();
}
synchronized(waiter){
if (Thread.currentThread().holdsLock(waiter))
System.out.println(Thread.currentThread().getName() + " holding the lock before notify call");
waiter.notify();
if (Thread.currentThread().holdsLock(waiter))
System.out.println(Thread.currentThread().getName() + " holding the lock after notify call");
else
System.out.println(Thread.currentThread().getName() + " IS NOT holding the lock after notify call");
}
if (Thread.currentThread().holdsLock(waiter))
System.out.println(Thread.currentThread().getName() + "holding outside the synchronized block");
else
System.out.println(Thread.currentThread().getName() + "IS NOT holding outside the synchronized block");

}
}
}

public class Runnables {

public static void main(String[] args) {
Waiter waiter = new Waiter();
Thread t1 = new Thread(waiter, "Waiter");
Thread t2 = new Thread(new Notifier(waiter), "Notifier");
t1.start();
t2.start();
}
}

</code>

thank you


Regards,
Alan Mehio
London, UK
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Beginner: Threads vs. Runnables