Blocking | CodeGuru

Blocking

Bruce Eckel’s Thinking in Java Contents | Prev | Next A thread can be in any one of four states: New: the thread object has been created but it hasn’t been started yet so it cannot run. Runnable: This means that a thread can be run when the time-slicing mechanism has CPU cycles available for […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 1, 2001
12 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

A


thread can be in any one of four

states:
  1. New:
    the thread object has been created but it hasn’t been started yet so it
    cannot run.
  2. Runnable:
    This means that a thread
    can
    be run when the time-slicing mechanism has CPU cycles available for the thread.
    Thus, the thread might or might not be running, but there’s nothing to
    prevent it from being run if the scheduler can arrange it; it’s not dead
    or blocked.
  3. Dead:
    the normal way for a thread to die is by returning from its
    run( )
    method.
    You can also call
    stop( ),
    but this throws an exception that’s a subclass of
    Error
    (which means you usually don’t catch it). Remember that throwing an
    exception should be a special event and not part of normal program execution;
    thus the use of
    stop( )
    is discouraged (and it’s deprecated in Java 1.2
    ).
    There’s also a
    destroy( )
    method (which has never been implemented) that you should never call if you can
    avoid it since it’s drastic and doesn’t release object locks.
  4. Blocked:
    the thread could be run but there’s something that prevents it. While a
    thread is in the blocked state the scheduler will simply skip over it and not
    give it any CPU time. Until a thread re-enters the runnable state it
    won’t perform any operations.

Becoming
blocked

The


blocked state is the most interesting and is worth further examination. A


thread can become blocked for five reasons:

  1. You’ve
    put the thread to sleep by calling sleep(milliseconds),
    in which case it will not be run for the specified time.
  2. You’ve
    suspended the execution of the thread with suspend( ).
    It will not become runnable again until the thread gets the
    resume( )
    message.
  3. You’ve
    suspended the execution of the thread with wait( ).
    It will not become runnable again until the thread gets the
    notify( )
    or
    notifyAll( )
    message. (Yes, this looks just like number 2, but there’s a distinct
    difference that will be revealed.)
  4. The
    thread
    is waiting for some IO to complete.
  5. The
    thread is trying to call a synchronized
    method
    on another object and that object’s lock is not available.

You


can also call

yield( )
(a method of the
Thread
class)
to voluntarily give up the CPU so that other threads can run. However, the same
thing happens if the scheduler decides that your thread has had enough time and
jumps to another thread. That is, nothing prevents the scheduler from
re-starting your thread. When a thread is blocked, there’s some reason
that it cannot continue running.

The


following example shows all five ways of becoming blocked. It all exists in a


single file called


Blocking.java,

but it will be examined here in discrete pieces. (You’ll notice the


“Continued” and “Continuing” tags that allow the tool


shown in Chapter 17 to piece everything together.) First, the basic framework:

//: Blocking.java
// Demonstrates the various ways a thread
// can be blocked.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.io.*;
 
//////////// The basic framework ///////////
class Blockable extends Thread {
  private Peeker peeker;
  protected TextField state = new TextField(40);
  protected int i;
  public Blockable(Container c) {
    c.add(state);
    peeker = new Peeker(this, c);
  }
  public synchronized int read() { return i; }
  protected synchronized void update() {
    state.setText(getClass().getName()
      + " state: i = " + i);
  }
  public void stopPeeker() {
    // peeker.stop(); Deprecated in Java 1.2
    peeker.terminate(); // The preferred approach
  }
}
 
class Peeker extends Thread {
  private Blockable b;
  private int session;
  private TextField status = new TextField(40);
  private boolean stop = false;
  public Peeker(Blockable b, Container c) {
    c.add(status);
    this.b = b;
    start();
  }
  public void terminate() { stop = true; }
  public void run() {
    while (!stop) {
      status.setText(b.getClass().getName()
        + " Peeker " + (++session)
        + "; value = " + b.read());
       try {
        sleep(100);
      } catch (InterruptedException e){}
    }
  }
} ///:Continued 

The


Blockable

class


is meant to be a base class for all the classes in this example that


demonstrate blocking. A


Blockable

object contains a


TextField

called


state

that is used to display information about the object. The method that displays


this information is


update( )

.


You can see it uses


getClass( ).getName( )

to produce the name of the class instead of just printing it out; this is


because


update( )

cannot know the exact name of the class it is called for, since it will be a


class derived from


Blockable

.

The


indicator of change in


Blockable

is an


int
i,

which will be incremented by the


run( )

method of the derived class.

There’s


a thread of class


Peeker

that is started for each


Blockable

object, and the


Peeker

’s


job is to watch its associated


Blockable

object to see changes in


i

by


calling


read( )

and reporting them in its


status
TextField

.


This is important: Note that


read( )

and


update( )

are both


synchronized

,


which means they require that the object lock be free.


Sleeping

The


first test in this program is with

sleep( ):
///:Continuing
///////////// Blocking via sleep() ///////////
class Sleeper1 extends Blockable {
  public Sleeper1(Container c) { super(c); }
  public synchronized void run() {
    while(true) {
      i++;
      update();
       try {
        sleep(1000);
      } catch (InterruptedException e){}
    }
  }
}
 
class Sleeper2 extends Blockable {
  public Sleeper2(Container c) { super(c); }
  public void run() {
    while(true) {
      change();
       try {
        sleep(1000);
      } catch (InterruptedException e){}
    }
  }
  public synchronized void change() {
      i++;
      update();
  }
} ///:Continued 

In


Sleeper1

the entire


run( )

method is


synchronized

.


You’ll see that the


Peeker

associated with this object will run along merrily


until

you start the thread, and then the


Peeker

stops cold. This is one form of blocking: since


Sleeper1.run( )

is


synchronized

,


and once the thread starts it’s always inside


run( )

,


the method never gives up the object lock and the


Peeker

is blocked.

Sleeper2

provides a solution by making run un-


synchronized

.


Only the


change( )

method is


synchronized

,


which means that while


run( )

is in


sleep( )

,


the


Peeker

can access the


synchronized

method it needs, namely


read( )

.


Here you’ll see that the


Peeker

continues running when you start the


Sleeper2

thread.


Suspending
and resuming

The


next part of the example introduces the concept of suspension. The


Thread

class has a method

suspend( )
to temporarily halt the thread and
resume( )
that re-starts it at the point it was halted. Presumably,
resume( )
is called by some thread outside the suspended one, and in this case
there’s a separate class called
Resumer
that does just that. Each of the classes demonstrating suspend/resume has an
associated resumer:
///:Continuing
/////////// Blocking via suspend() ///////////
class SuspendResume extends Blockable {
  public SuspendResume(Container c) {
    super(c);
    new Resumer(this);
  }
}
 
class SuspendResume1 extends SuspendResume {
  public SuspendResume1(Container c) { super(c);}
  public synchronized void run() {
    while(true) {
      i++;
      update();
      suspend(); // Deprecated in Java 1.2
    }
  }
}
 
class SuspendResume2 extends SuspendResume {
  public SuspendResume2(Container c) { super(c);}
  public void run() {
    while(true) {
      change();
      suspend(); // Deprecated in Java 1.2
    }
  }
  public synchronized void change() {
      i++;
      update();
  }
}
 
class Resumer extends Thread {
  private SuspendResume sr;
  public Resumer(SuspendResume sr) {
    this.sr = sr;
    start();
  }
  public void run() {
    while(true) {
       try {
        sleep(1000);
      } catch (InterruptedException e){}
      sr.resume(); // Deprecated in Java 1.2
    }
  }
} ///:Continued 
SuspendResume1

also has a


synchronized
run( )

method. Again, when you start this thread you’ll see that its associated


Peeker

gets blocked waiting for the lock to become available, which never happens.


This is fixed as before in


SuspendResume2

,


which does not


synchronize

the entire


run( )

method but instead uses a separate


synchronized
change( )

method.

You


should be aware that Java 1.2


deprecates the use of
suspend( )
and
resume( ),
because
suspend( )
holds the object’s lock and is thus
deadlock-prone.
That is, you can easily get a number of locked objects waiting on each other,
and this will cause your program to freeze. Although you might see them used in
older programs you should not use
suspend( )
and
resume( ).
The proper solution is described later in this chapter.


Wait
and notify

The


point with the first two examples is that both


sleep( )

and


suspend( )
do
not

release


the lock as they are called. You must be aware of this when working with locks.


On the other hand, the method

wait( )
does
release the lock when it is called, which means that other
synchronized
methods in the thread object could be called during a
wait( ).
In the following two classes, you’ll see that the
run( )
method is fully
synchronized
in both cases, however, the
Peeker
still has full access to the
synchronized
methods during a
wait( ).
This is because
wait( )
releases the lock on the object as it suspends the method it’s called
within.

You’ll


also see that there are two forms of


wait( ).

The first takes an argument in milliseconds that has the same meaning as in


sleep( )

:


pause for this period of time. The difference is that in


wait( )

,


the object lock is released


and

you can come out of the


wait( )

because of a


notify( )

as well as having the clock run out.

The


second form takes no arguments, and means that the


wait( )

will continue until a


notify( )

comes along and will not automatically terminate after a time.

One


fairly unique aspect of


wait( )

and


notify( )

is that both methods are part of the base class


Object

and not part of


Thread

as are


sleep( )

,


suspend( )

,


and


resume( )

.


Although this seems a bit strange at first – to have something


that’s exclusively for threading as part of the universal base class


– it’s essential because they manipulate the lock that’s also


part of every object. As a result, you can put a


wait( )

inside any


synchronized

method, regardless of whether there’s any threading going on inside that


particular class. In fact, the


only

place you can call


wait( )

is within a


synchronized

method or block. If you call


wait( )

or


notify( )

within a method that’s not


synchronized,

the program will compile, but when you run it you’ll get an

IllegalMonitorStateException
with the somewhat non-intuitive message “current thread not owner.”
Note that
sleep( ),
suspend( ),
and
resume( )
can all be called within non-
synchronized
methods since they don’t manipulate the lock.

You


can call


wait( )

or


notify( )

only for your own lock. Again, you can compile code that tries to use the wrong


lock, but it will produce the same


IllegalMonitorStateException

message as before. You can’t fool with someone else’s lock, but you


can ask another object to perform an operation that manipulates its own lock.


So one approach is to create a


synchronized

method that calls


notify( )

for its own object. However, in


Notifier

you’ll see the


notify( )

call inside a


synchronized

block:

synchronized(wn2) {
  wn2.notify();
}

where


wn2

is the object of type


WaitNotify2

.


This method, which is not part of


WaitNotify2

,


acquires the lock on the


wn2

object, at which point it’s legal for it to call


notify( )

for


wn2

and you won’t get the


IllegalMonitorStateException

.

///:Continuing
/////////// Blocking via wait() ///////////
class WaitNotify1 extends Blockable {
  public WaitNotify1(Container c) { super(c); }
  public synchronized void run() {
    while(true) {
      i++;
      update();
       try {
        wait(1000);
      } catch (InterruptedException e){}
    }
  }
}
 
class WaitNotify2 extends Blockable {
  public WaitNotify2(Container c) {
    super(c);
    new Notifier(this);
  }
  public synchronized void run() {
    while(true) {
      i++;
      update();
       try {
        wait();
      } catch (InterruptedException e){}
    }
  }
}
 
class Notifier extends Thread {
  private WaitNotify2 wn2;
  public Notifier(WaitNotify2 wn2) {
    this.wn2 = wn2;
    start();
  }
  public void run() {
    while(true) {
       try {
        sleep(2000);
      } catch (InterruptedException e){}
      synchronized(wn2) {
        wn2.notify();
      }
    }
  }
} ///:Continued 
wait( )

is typically used when you’ve gotten to the point where you’re


waiting for some other condition, under the control of forces outside your


thread, to change and you don’t want to idly wait by inside the thread. So


wait( )

allows you to put the thread to sleep while waiting for the world to change,


and only when a


notify( )

or


notifyAll( )

occurs


does the thread wake up and check for changes. Thus, it provides a way to


synchronize between threads.



Blocking
on IO

If


a stream is waiting for some IO activity, it will automatically block. In the


following portion of the example, the two classes work with generic

Reader
and
Writer
objects (using the Java 1.1

Streams), but in the test framework a
piped
stream will be set up to allow the two threads to safely pass data to each
other (which is the purpose of piped streams).

The


Sender

puts data into the


Writer

and sleeps for a random amount of time. However,


Receiver

has no


sleep( )

,


suspend( )

,


or


wait( )

.


But when it does a


read( )

it automatically blocks when there is no more data.

///:Continuing
class Sender extends Blockable { // send
  private Writer out;
  public Sender(Container c, Writer out) {
    super(c);
    this.out = out;
  }
  public void run() {
    while(true) {
      for(char c = 'A'; c <= 'z'; c++) {
         try {
          i++;
          out.write(c);
          state.setText("Sender sent: "
            + (char)c);
          sleep((int)(3000 * Math.random()));
        } catch (InterruptedException e){}
          catch (IOException e) {}
      }
    }
  }
}
 
class Receiver extends Blockable {
  private Reader in;
  public Receiver(Container c, Reader in) {
    super(c);
    this.in = in;
  }
  public void run() {
    try {
      while(true) {
        i++; // Show peeker it's alive
        // Blocks until characters are there:
        state.setText("Receiver read: "
          + (char)in.read());
      }
    } catch(IOException e) { e.printStackTrace();}
  }
} ///:Continued 

Both


classes also put information into their


state

fields and change


i

so


the


Peeker

can see that the thread is running.


Testing

The


main applet class is surprisingly simple because most of the work has been put


into the


Blockable

framework. Basically, an array of


Blockable

objects is created, and since each one is a thread, they perform their own


activities when you press the “start” button. There’s also a


button and


actionPerformed( )

clause to stop all of the


Peeker

objects, which provides a demonstration of the alternative to the deprecated


(in Java 1.2

)
stop( )
method of
Thread.

To


set up a connection between the


Sender

and


Receiver

objects, a


PipedWriter

and


PipedReader

are created. Note that the


PipedReader
in

must


be connected to the


PipedWriter
out

via


a constructor argument. After that, anything that’s placed in


out

can later be extracted from


in

,


as if it passed through a pipe (hence the name). The


in

and


out

objects are then passed to the


Receiver

and


Sender

constructors, respectively, which treat them as


Reader

and


Writer

objects


of any type (that is, they are upcast).

The


array of


Blockable

handles


b

is not initialized at its point of definition because the piped streams cannot


be set up before that definition takes place (the need for the


try

block prevents this).

///:Continuing
/////////// Testing Everything ///////////
public class Blocking extends Applet {
  private Button
    start = new Button("Start"),
    stopPeekers = new Button("Stop Peekers");
  private boolean started = false;
  private Blockable[] b;
  private PipedWriter out;
  private PipedReader in;
  public void init() {
     out = new PipedWriter();
    try {
      in = new PipedReader(out);
    } catch(IOException e) {}
    b = new Blockable[] {
      new Sleeper1(this),
      new Sleeper2(this),
      new SuspendResume1(this),
      new SuspendResume2(this),
      new WaitNotify1(this),
      new WaitNotify2(this),
      new Sender(this, out),
      new Receiver(this, in)
    };
    start.addActionListener(new StartL());
    add(start);
    stopPeekers.addActionListener(
      new StopPeekersL());
    add(stopPeekers);
  }
  class StartL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      if(!started) {
        started = true;
        for(int i = 0; i < b.length; i++)
          b[i].start();
      }
    }
  }
  class StopPeekersL implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      // Demonstration of the preferred 
      // alternative to Thread.stop():
      for(int i = 0; i < b.length; i++)
        b[i].stopPeeker();
    }
  }
  public static void main(String[] args) {
    Blocking applet = new Blocking();
    Frame aFrame = new Frame("Blocking");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(350,550);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~ 

In


init( )

,


notice the loop that moves through the entire array and adds the


state

and


peeker.status

text fields to the page.

When


the


Blockable

threads


are initially created, each one automatically creates and starts its own


Peeker

.


So you’ll see the


Peeker

s


running before the


Blockable

threads are started. This is essential, as some of the


Peeker

s


will get blocked and stop when the


Blockable

threads start, and it’s essential to see this to understand that


particular aspect of blocking.


Deadlock

Because


threads can become blocked


and

because objects can have


synchronized

methods that prevent threads from accessing that object until the


synchronization lock is released, it’s possible for one thread to get


stuck waiting for another thread, which in turn waits for another thread, etc.,


until the chain leads back to a thread waiting on the first one. Thus,


there’s a continuous loop of threads waiting on each other and no one can


move. This is called


deadlock

.


The claim is that it doesn’t happen that often, but when it happens to


you it’s frustrating to debug.

There


is no language support to help prevent deadlock; it’s up to you to avoid


it by careful design. These are not comforting words to the person who’s


trying to debug a deadlocking program.


The
deprecation of stop( ), suspend( ),

resume( ),
and destroy( ) in Java 1.2

One


change that has been made in Java 1.2


to reduce the possibility of deadlock is the deprecation of
Thread’s
stop( ),
suspend( ),
resume( ),
and
destroy( )
methods.

The


reason that the


stop( )
method
is deprecated is because it is unsafe. It releases all the locks that the
thread had acquired, and if the objects are in an inconsistent state
(“damaged”) other threads can view and modify them in that state.
The resulting problems can be subtle and difficult to detect. Instead of using
stop( ),
you should follow the example in
Blocking.java
and use a flag to tell the thread when to terminate itself by exiting its
run( )
method.

There


are times when a thread blocks, such as when it is waiting for input, and it


cannot poll a flag as it does in


Blocking.java

.


In these cases, you still shouldn’t use


stop( )

,


but instead you can use the

interrupt( )
method in
Thread
to break out of the blocked code:
//: Interrupt.java
// The alternative approach to using stop()
// when a thread is blocked
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
 
class Blocked extends Thread {
  public synchronized void run() {
    try {
      wait(); // Blocks
    } catch(InterruptedException e) {
      System.out.println("InterruptedException");
    }
    System.out.println("Exiting run()");
  }
}
 
public class Interrupt extends Applet {
  private Button
    interrupt = new Button("Interrupt");
  private Blocked blocked = new Blocked();
  public void init() {
    add(interrupt);
    interrupt.addActionListener(
      new ActionListener() {
        public
        void actionPerformed(ActionEvent e) {
          System.out.println("Button pressed");
          if(blocked == null) return;
          Thread remove = blocked;
          blocked = null; // to release it
          remove.interrupt();
        }
      });
    blocked.start();
  }
  public static void main(String[] args) {
    Interrupt applet = new Interrupt();
    Frame aFrame = new Frame("Interrupt");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(200,100);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~ 

The


wait( )

inside


Blocked.run( )

produces the blocked thread. When you press the button, the


blocked

handle is set to


null

so the garbage collector will clean it up, and then the object’s


interrupt( )

method is called. The first time you press the button you’ll see that the


thread quits, but after that there’s no thread to kill so you just see


that the button has been pressed.

The
suspend( )
and
resume( )
methods turn out to be inherently deadlock-prone. When you call
suspend( ),
the target thread stops but it still holds any locks that it has acquired up to
that point. So no other thread can access the locked resources until the thread
is resumed. Any thread that wants to resume the target thread and also tries to
use any of the locked resources produces deadlock. You should not use
suspend( )
and
resume( ),
but instead put a flag in your
Thread
class to indicate whether the thread should be active or suspended. If the flag
indicates that the thread is suspended,

the thread goes into a wait using
wait( ).
When the flag indicates that the thread should be resumed the thread is
restarted with
notify( ).
An example can be produced by modifying
Counter2.java.
Although the effect is similar, you’ll notice that the code organization
is quite different –
anonymous
inner classes are used for all of the listeners and the
Thread
is an inner class, which makes programming slightly more convenient since it
eliminates some of the extra bookkeeping necessary in
Counter2.java:
//: Suspend.java
// The alternative approach to using suspend()
// and resume(), which have been deprecated
// in Java 1.2.
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
 
public class Suspend extends Applet {
  private TextField t = new TextField(10);
  private Button
    suspend = new Button("Suspend"),
    resume = new Button("Resume");
  class Suspendable extends Thread {
    private int count = 0;
    private boolean suspended = false;
    public Suspendable() { start(); }
    public void fauxSuspend() {
      suspended = true;
    }
    public synchronized void fauxResume() {
      suspended = false;
      notify();
    }
    public void run() {
      while (true) {
        try {
          sleep(100);
          synchronized(this) {
            while(suspended)
              wait();
          }
        } catch (InterruptedException e){}
        t.setText(Integer.toString(count++));
      }
    }
  }
  private Suspendable ss = new Suspendable();
  public void init() {
    add(t);
    suspend.addActionListener(
      new ActionListener() {
        public
        void actionPerformed(ActionEvent e) {
          ss.fauxSuspend();
        }
      });
    add(suspend);
    resume.addActionListener(
      new ActionListener() {
        public
        void actionPerformed(ActionEvent e) {
          ss.fauxResume();
        }
      });
    add(resume);
  }
  public static void main(String[] args) {
    Suspend applet = new Suspend();
    Frame aFrame = new Frame("Suspend");
    aFrame.addWindowListener(
      new WindowAdapter() {
        public void windowClosing(WindowEvent e){
          System.exit(0);
        }
      });
    aFrame.add(applet, BorderLayout.CENTER);
    aFrame.setSize(300,100);
    applet.init();
    applet.start();
    aFrame.setVisible(true);
  }
} ///:~ 

The


flag


suspended

inside


Suspendable

is used to turn suspension on and off. To suspend, the flag is set to


true

by calling


fauxSuspend( )

and


this is detected inside


run( )

.


The


wait( )

,


as described earlier in this chapter, must be


synchronized

so that it has the object lock. In


fauxResume( )

,


the


suspended

flag is set to


false

and


notify( )

is called – since this wakes up


wait( )

inside a


synchronized

clause the


fauxResume( )

method must also be


synchronized

so that it acquires the lock before calling


notify( )

(thus the lock is available for the


wait( )

to wake up with). If you follow the style shown in this program you can avoid


using


wait( )

and


notify( )

.

The


destroy( )
method of
Thread
has
never been implemented; it’s like a
suspend( )
that cannot resume, so it has the same deadlock issues as
suspend( ).
However, this is not a deprecated method and it might be implemented in a
future version of Java (after 1.2) for special situations in which the risk of
a deadlock is acceptable.

You


might wonder why these methods, now deprecated, were included in Java in the


first place. It seems a clear admission of a rather significant mistake to


simply remove them outright (and pokes yet another hole in the arguments for


Java’s exceptional design and infallibility touted by Sun marketing


people). The heartening part about the change is that it clearly indicates that


the technical people and not the marketing people are running the show –


they discovered a problem and they are fixing it. I find this much more


promising and hopeful than leaving the problem in because fixing it would admit


an error. It means that Java will continue to improve, even if it means a


little discomfort on the part of Java programmers. I’d rather deal with


the discomfort than watch the language stagnate.


Contents

|

Prev

|

Next
CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.