简体   繁体   中英

Java sub-class updateting with wait-notify

Note: feel free to edit/comment if this wait and notify uses incorrect syntax.

You have a class that has a calculation that is only done by a different thread:

class Foo{
   public Foo() {
      //so thread 2 can know about us. So much for design patterns.
      synchronized(GlobalStuff) {GlobalStuff.threadpool.add(this);} 
   }

   Bar b;
   public Bar emptyBar() { //called by thread #1 ("your" thread).
     synchronized(this) {
        b = new Bar();
        return b;
     }
   }
   public void makeTest() { //Thread #2 periodically runs this block of code.
      synchronized(this) {
         if (b==null) {return;} //do nothing if it is still null.
         if (b.hasBeenMadeIntoExam();) {return;} //do nothing if it is done already.

         b.makeMeAnAnnoyingExam();
         ....
         this.notifyAll(); //do we even need the "this"?
      }
   }
}

Here is how you wait for it:

//thread 1 runs this block of code.
Foo fooey = new Foo();
Bar b = fooey.emptyBar();
while( b.equals(fooey.emptyBar()) ) { //some statement to check whether it is done or not
   try { //mandatory try catch statements to keep Java verbose.
       fooey.makeTest();
       fooey.wait(); //wait, and fooey will free us when it calls notifyAll()
   } catch (InterruptedException ex) {}
}
.... //more code that depends on the exam being made.

My concern is that b's fields are not volatile (even if we changed b to be volatile), so when thread #2 updates them, they don't immediately appear for thread 1. Remember, synchronizing and notify are not "deep" so they don't meticulously update the state of all sub-classes. Do I need to worry about it? Is there a way to fix this without manually sticking "volatile" everywhere?

I generally avoid using 'this' for synchronized. Instead of using synchronized(this), define an explicit lock and synchronize against that. If subclasses need it, then make it available to them as well. Eg

class Foo {

  protected final Object lock = new Object();

  public Bar emptyBar() {
    synchronized (lock) { 
      ...
    }
  }

  ...

}

And instead of this.notifyAll(), use lock.notifyAll();.

So long as all fields that you want to read/write are accessed/updated within the synchronized(lock) blocks you can rest assured that the values are the most recent.

Instead of synchronizing whole instance. You can synchronize only method.

Bar b; public synchronized Bar emptyBar() { //called by thread #1 ("your" thread). b = new Bar(); return b; }

Instead of making adding synchronized blocks in Foo. You can synchronize methods in Bar which changes state of object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM