On CBS.com: Canadians are cool

Calling wait, notify, and notifyAll within a non-synchronized method

Tags: David Petersheim, notifyAll, LockTip, LongSupplier, Java Tips Newsletter

  • Save
  • Print
  • Digg This
  • 3

Takeaway: Locks and monitors are important topics in multi-threaded programming. For instance, find out why if you need to call wait(), notify(), or notifyAll() from within a non-synchronized method, you must first obtain a lock on the object's monitor.

You may be used to seeing the wait(), notify(), and notifyAll() methods called within synchronized methods. But here's a subtlety that you may not know: The caller of the wait(), notify(), and notifyAll() methods is required to own the monitor for which it's invoking these methods. This point sometimes goes unnoticed because programmers are used to calling these methods from within synchronized methods.

If you need to call wait(), notify(), or notifyAll() from within a non-synchronized method, then you must first obtain a lock on the object's monitor. If you don't, an exception will be generated when an attempt is made to call the method in question.

Here's an example of a class that manipulates Long objects and a class that supplies Longs to be manipulated:

import java.util.List;
import java.util.ArrayList;

public class LockTip extends Thread {
    private List longs = new ArrayList();

    public static void main(String args[]) {
        LockTip lt = new LockTip();
        lt.start();

        new LongSupplier(lt).start();
    }

    public void run() {
        while (true) {
            try {
                wait();

                // do something with longs
                System.out.println("doing something: " + this.longs);
            }
            catch (InterruptedException e) {}
        }
    }

    public void addLong(Long l) {
         this.longs.add(l);
         notifyAll();
    }
}

class LongSupplier extends Thread {
    private LockTip lt;

    public LongSupplier(LockTip lt) {
        this.lt = lt;
    }


    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                this.lt.addLong(new Long(123));
            }
            catch (InterruptedException e) {}
        }
    }
}

This code will compile and run, but the first time there's an attempt to execute the wait() or notifyAll() methods, an exception will be thrown:

java.lang.IllegalMonitorStateException: current thread not owner
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:426)
        at LockTip.run(LockTip.java:18)

While the fix for this problem is simple, it isn't necessarily obvious. You have two options: add the keyword synchronized to the method definition or synchronize on the "this" keyword. In this case, either option is equally valid.

The following code has been modified using the second option, synchronizing on "this":

import java.util.List;
import java.util.ArrayList;

public class LockTip extends Thread {
    private List longs = new ArrayList();

    public static void main(String args[]) {
        LockTip lt = new LockTip();
        lt.start();

        new LongSupplier(lt).start();
    }

    public void run() {
        while (true) {
            try {
                synchronized(this) {
                    wait();
                }
                // do something with longs
                System.out.println("doing something: " + this.longs);

            }
            catch (InterruptedException e) {}
        }
    }

    public void addLong(Long l) {
        synchronized(this) {
            this.longs.add(l);
            notifyAll();
        }
    }
}


class LongSupplier extends Thread {
    private LockTip lt;

    public LongSupplier(LockTip lt) {
        this.lt = lt;
    }


    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                this.lt.addLong(new Long(123));
            }
            catch (InterruptedException e) {}
        }
    }
}

Now when the methods are called no exception is thrown.

Locks and monitors are important topics in multi-threaded programming. The Java language was designed with threads in mind, but programmers still have to make choices. Read more about it in the Javadoc for java.lang.Thread.

Delivered each Thursday, our free Java newsletter provides insight and hands-on tips you need to unlock the full potential of this programming language. Automatically sign up today!

  • Save
  • Print
  • Digg This
  • 3

What do you think?

Article Categories

Security
Security Solutions, IT Locksmith
Networking and Communications
E-mail Administration NetNote, Cisco Routers and Switches
CIO and IT Management
Project Management, CIO Issues, Strategies that Scale
Desktops, Laptops & OS
Windows 2000 Professional, Microsoft Word, Microsoft Excel, Microsoft Access, Windows XP,
Data Management
Oracle, SQL Server
Servers
Windows NT, Linux NetNote, Windows Server 2003
Career Development
Geek Trivia
Software/Web Development
Web Development Zone, Visual Basic, .NET

The Green Enterprise

advertisement
Click Here