File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
Win a copy of Soft Skills: The software developer's life manual this week in the Jobs Discussion forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

What's wrong with this code? (trying wait and notifyall for first time...)

 
M Marsden
Greenhorn
Posts: 21
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, the following was my attempt to do the programming project on threads on page 233 of the 2005 ed. of Heller and Roberts Complete Java 2 Certification. (I know the answer's on the CD, but I got the book from the library and the CD was missing.) The basic point of the question was to have one Rendezvous and several Waiters (specified by command-line) all going to the hurry up and wait and get notified and come back at different times. (So you could see how the threads would return in different orders, presumably.) My program never gets past the first Waiter, for some reason. Little help? (Thanks!

class Rendezvous {
static int i;
synchronized void hurryUpAndWait() {
i++;
try {
wait();
} catch (InterruptedException ex) { }
}
}

class Waiter extends Thread {
int waiterid;
Rendezvous rendewait = new Rendezvous();
Waiter(Rendezvous rende) {
waiterid += 1;
rende=rendewait;
run();
}
public void run() {
System.out.println("starting run for " +waiterid);
rendewait.hurryUpAndWait();
System.out.println("Notification has happened for Waiter ID #"+waiterid);
}
}
public class NotifyLab {


public static void main(String[] args) {
int x = Integer.parseInt(args[0]);
Rendezvous rennot = new Rendezvous();
Waiter[] newwaiter = new Waiter[x];
while (x > 0) {
newwaiter[x] = new Waiter(rennot);
newwaiter[x].start();
System.out.println(x +"newwaiter was started.");
x--;
}

rennot.notifyAll();
}

}
 
Ernest Friedman-Hill
author and iconoclast
Marshal
Pie
Posts: 24204
34
Chrome Eclipse IDE Mac OS X
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, without going into every detail, I see two or three major things wrong here. First, I see that nothing calls "notify" until every thread has been started; perhaps that's intentional. I really can't tell what the logic is supposed to be.

But... wait() and notify() operate with respect to individual objects, and generally, the idea is that multiple things are competing to wait on one single object. But you're creating a zillion Rendezvous objects, even though clearly the whole point of the exercise is for all the threads to share a single one, communicating through it.

Also in the Waiter constructor, you set the constructor parameter equal to the already-initialized member, when perhaps you mean to do just the opposite.
 
Norm Radder
Ranch Hand
Posts: 707
3
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
<blockquote>code:
<pre name="code" class="java">
int x = Integer.parseInt(args[0]);
Rendezvous rennot = new Rendezvous();
Waiter[] newwaiter = new Waiter[x];
while (x > 0) {
newwaiter[x] = new Waiter(rennot);
</pre>
</blockquote>

Seems like this code should get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
The size of the array (x) is used as the value of its index. BOOM!
[ July 11, 2008: Message edited by: Norm Radder ]
 
M Marsden
Greenhorn
Posts: 21
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Okay, thanks for the feedback -- I've cleaned the code up some and it's almost working, I feel, (it's building several threads at least now), but when it hits the notifyAll, I get "current thread not owner"... any idea why? Here's the latest version:


[HENRY: Added Code Tags]
[ July 13, 2008: Message edited by: Henry Wong ]
 
Norm Radder
Ranch Hand
Posts: 707
3
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
One thing wrong with your program is you don't explain with comments in the code why each Waiter creates a new Rendezvous(); in the run method. You create one in the main() method also.

I recommend another pass thru your textbook to see how synchronized and monitors work and how to use wait() and notifyAll(). They only work if they are used in the same object. If there are lots of new object floating around, its not going to work.
 
Henry Wong
author
Marshal
Pie
Posts: 20820
75
C++ Chrome Eclipse IDE Firefox Browser Java jQuery Linux VI Editor Windows
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
but when it hits the notifyAll, I get "current thread not owner"... any idea why?


There are actually quite a few things wrong with your application... but to answer your question...



To call the notifyAll() method, of the object referred to by the rennot variable, you need to own the lock of that object. Synchronizing on the newwaiter reference only works, if both references happen to refer to the same object.

Henry
 
M Marsden
Greenhorn
Posts: 21
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the feedback everyone - I still haven't quite got this, but I feel like I'm getting closer - I think I'm down to one Rendezvous instance, for example (which is how it should be...) The problem with the following code is that the run() method can't see the rennot argument -- how do I pass the Rendezvous from the constructor to the run method?

class Rendezvous {
static int i;
synchronized void hurryUpAndWait() {
i++;
try {
wait();
} catch (InterruptedException ex) { }
}
}

class Waiter extends Thread {
static int waiteridpool;
int waiterid = waiteridpool;
Waiter(Rendezvous rennot) {
waiteridpool += 1;
start();
}

public void run() {
System.out.println("starting run for " +waiterid);
// Can't seem to access rennot from within the run method
// There's a 'cannot find symbol' error on the next line
rennot.hurryUpAndWait();
System.out.println("Notification has happened for Waiter ID #"+waiterid);
}
}
public class NotifyLab {
public static void main(String[] args) {
int x = Integer.parseInt(args[0]);
Rendezvous rennot = new Rendezvous();
Waiter[] newwaiter = new Waiter[x];
while (x > 0) {
newwaiter[x-1] = new Waiter(rennot);
System.out.println(x +"newwaiter was started.");
x--;
}
}

}
 
Norm Radder
Ranch Hand
Posts: 707
3
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
basic point of the question was to have one Rendezvous and several Waiters ... all going to the hurry up and wait and get notified and come back at different times.

What does this mean? How does the program show success?

For a method (run) in the Waiter class to see the value of an arg(rennot) to the Constructor, the Constructor needs to save it(rennot) in a class variable.

I don't see the notifyAll() to get any waiting threads started again.
[ July 13, 2008: Message edited by: Norm Radder ]
 
M Marsden
Greenhorn
Posts: 21
  • 0
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, the point of the program is to get several threads running and see what order they come back in when notifyAll runs. I've finally got a version of the program running that seems to do that - thanks to everyone who commented. I'm not 100% sure this program is operating correctly though, since there's supposed to be one Rendezvous instance, and I feel like I've got two at least (since I've got two 'new' Rendevous), but they may end up referring to the same Object - it seems like the one in NotifyLab is a dummy object that just gets the Waiter constructor to run to me, and probably could be eliminated...

class Rendezvous {
static int i;
synchronized void hurryUpAndWait() {
i++;
try {
wait();
} catch (InterruptedException ex) { }
}
}

class Waiter extends Thread {
static int waiteridpool;
int waiterid = waiteridpool;
static Rendezvous rennotW = new Rendezvous();
Waiter(Rendezvous rennotN) {
rennotN=rennotW;
waiteridpool += 1;
start();
}

public void run() {
System.out.println("starting run for " +waiterid);
rennotW.hurryUpAndWait();
System.out.println("Notification has happened for Waiter ID #"+waiterid);
}
}
public class NotifyLab {
Rendezvous rennot;
public static void main(String[] args) {
int x = Integer.parseInt(args[0]);
Rendezvous rennot = new Rendezvous();
Waiter[] newwaiter = new Waiter[x];
while (x > 0) {
newwaiter[x-1] = new Waiter(rennot);
System.out.println(x +"newwaiter was started.");
x--;
}
synchronized(Waiter.rennotW) {
Waiter.rennotW.notifyAll();
System.out.println("Just notifyAll-ed");
}
}
}
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic