Question on Daemon thread

Discussion in 'Java' started by ankur, Dec 27, 2008.

  1. ankur

    ankur Guest

    This code defines 3 threads A, B and C as Daemon threads. However they
    continue to push and pop on the Stack even after the main thread (user
    thread) has died. How is that possible ? Because Daemon threads exist
    only so long as user threads exist..isn't it ?

    package pack4;

    class StackImpl1 {
    private Object[] stackArray;
    private volatile int topOfStack;

    StackImpl1 (int capacity) {
    stackArray = new Object[capacity];
    topOfStack = -1;
    }

    public synchronized Object pop() {
    System.out.println(Thread.currentThread() + ": popping");

    while (isEmpty())
    try {
    System.out.println(Thread.currentThread() + ": waiting
    to pop");
    wait(); // (1)
    } catch (InterruptedException e) { }
    Object obj = stackArray[topOfStack];
    stackArray[topOfStack--] = null;
    System.out.println(Thread.currentThread() + ": notifying after
    pop");
    notify(); // (2)
    return obj;
    }

    public synchronized void push(Object element) {
    System.out.println(Thread.currentThread() + ": pushing");
    while (isFull())
    try {
    System.out.println(Thread.currentThread() + ": waiting
    to push");
    wait(); // (3)
    } catch (InterruptedException e) { }
    stackArray[++topOfStack] = element;
    System.out.println(Thread.currentThread() + ": notifying after
    push");
    notify(); // (4)
    }

    public boolean isFull() { return topOfStack >= stackArray.length
    -1; }
    public boolean isEmpty() { return topOfStack < 0; }
    }

    abstract class StackUser extends Thread { // (5) Stack user

    protected StackImpl1 stack; // (6)

    StackUser(String threadName, StackImpl1 stack) {
    super(threadName);
    this.stack = stack;
    System.out.println(this);
    setDaemon(true); // (7) Daemon
    thread
    start(); // (8) Start this
    thread
    }
    }

    class StackPopper extends StackUser { // (9) Popper
    StackPopper(String threadName, StackImpl1 stack) {
    super(threadName, stack);
    }
    public void run() { while (true) stack.pop(); }
    }

    class StackPusher extends StackUser { // (10) Pusher
    StackPusher(String threadName, StackImpl1 stack) {
    super(threadName, stack);
    }
    public void run() { while (true) stack.push(new Integer(1)); }
    }

    public class WaitAndNotifyClient {
    public static void main(String[] args)
    throws InterruptedException { // (11)

    StackImpl1 stack = new StackImpl1(5);

    new StackPusher("A", stack);

    new StackPusher("B", stack);

    new StackPopper("C", stack);

    System.out.println("Main Thread sleeping.");
    Thread.sleep(10);
    System.out.println("Exit from Main Thread.");
    }
    }


    Output : Observe that the pushing and popping continues even after the
    main thread has exited !

    Thread[A,5,main]
    Thread[B,5,main]
    Thread[C,5,main]
    Main Thread sleeping.
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Exit from Main Thread.---------------------------------------------
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: waiting to pop
    Thread[B,5,main]: notifying after push
    Thread[C,5,main]: notifying after pop
    Thread[C,5,main]: popping
    Thread[C,5,main]: waiting to pop
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: notifying after push
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: pushing
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[A,5,main]: pushing
    Thread[A,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
    Thread[B,5,main]: notifying after push
    Thread[B,5,main]: pushing
    Thread[B,5,main]: waiting to push
    Thread[A,5,main]: waiting to push
    Thread[C,5,main]: popping
    Thread[C,5,main]: notifying after pop
     
    ankur, Dec 27, 2008
    #1
    1. Advertising

  2. In article
    <>,
    ankur <> wrote:

    > This code defines 3 threads A, B and C as Daemon threads. However
    > they continue to push and pop on the Stack even after the main thread
    > (user thread) has died. How is that possible ? Because Daemon threads
    > exist only so long as user threads exist..isn't it ?


    Let's see:

    <http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.8>

    I would say your program's execution is compliant. It just takes a
    little time for the VM to reap your doomed daemons; or you can
    foreclose explicitly, as shown in this nicely wrapped version
    of your example:

    <sscce>
    public class WaitAndNotifyClient {

    public static void main(String[] args)
    throws InterruptedException {

    StackImpl1 stack = new StackImpl1(5);

    new StackPusher("A", stack);
    new StackPusher("B", stack);
    new StackPopper("C", stack);

    System.out.println("Main Thread sleeping.");
    Thread.sleep(10);
    System.out.println("Exit from Main Thread.");
    System.exit(1);
    }
    }

    class StackImpl1 {

    private Object[] stackArray;
    private volatile int topOfStack;

    StackImpl1(int capacity) {
    stackArray = new Object[capacity];
    topOfStack = -1;
    }

    public synchronized Object pop() {
    System.out.println(Thread.currentThread()
    + ": popping");

    while (isEmpty()) {
    try {
    System.out.println(Thread.currentThread()
    + ": waiting to pop");
    wait();
    } catch (InterruptedException e) {
    }
    }
    Object obj = stackArray[topOfStack];
    stackArray[topOfStack--] = null;
    System.out.println(Thread.currentThread()
    + ": notifying after pop");
    notify();
    return obj;
    }

    public synchronized void push(Object element) {
    System.out.println(Thread.currentThread()
    + ": pushing");
    while (isFull()) {
    try {
    System.out.println(Thread.currentThread()
    + ": waiting to push");
    wait();
    } catch (InterruptedException e) {
    }
    }
    stackArray[++topOfStack] = element;
    System.out.println(Thread.currentThread()
    + ": notifying after push");
    notify();
    }

    public boolean isFull() {
    return topOfStack >= stackArray.length - 1;
    }

    public boolean isEmpty() {
    return topOfStack < 0;
    }
    }

    abstract class StackUser extends Thread {

    protected StackImpl1 stack;

    StackUser(String threadName, StackImpl1 stack) {
    super(threadName);
    this.stack = stack;
    System.out.println(this);
    setDaemon(true);
    start();
    }
    }

    class StackPopper extends StackUser {

    StackPopper(String threadName, StackImpl1 stack) {
    super(threadName, stack);
    }

    public void run() {
    while (true) {
    stack.pop();
    }
    }
    }

    class StackPusher extends StackUser {

    StackPusher(String threadName, StackImpl1 stack) {
    super(threadName, stack);
    }

    public void run() {
    while (true) {
    stack.push(new Integer(1));
    }
    }
    }
    </sscce>

    --
    John B. Matthews
    trashgod at gmail dot com
    http://home.roadrunner.com/~jbmatthews/
     
    John B. Matthews, Dec 27, 2008
    #2
    1. Advertising

  3. ankur

    ankur Guest

    On Dec 27, 2:44 pm, "John B. Matthews" <> wrote:
    > In article
    > <>,
    >
    >  ankur <> wrote:
    > > This code defines 3 threads A, B and C as Daemon threads. However
    > > they continue to push and pop on the Stack even after the main thread
    > > (user thread) has died. How is that possible ? Because Daemon threads
    > > exist only so long as user threads exist..isn't it ?

    >
    > Let's see:
    >
    > <http://java.sun.com/docs/books/jls/third_edition/html/execution.html#...>
    >
    > I would say your program's execution is compliant. It just takes a
    > little time for the VM to reap your doomed daemons; or you can
    > foreclose explicitly, as shown in this nicely wrapped version
    > of your example:
    >
    > <sscce>
    > public class WaitAndNotifyClient {
    >
    >     public static void main(String[] args)
    >         throws InterruptedException {
    >
    >         StackImpl1 stack = new StackImpl1(5);
    >
    >         new StackPusher("A", stack);
    >         new StackPusher("B", stack);
    >         new StackPopper("C", stack);
    >
    >         System.out.println("Main Thread sleeping.");
    >         Thread.sleep(10);
    >         System.out.println("Exit from Main Thread.");
    >         System.exit(1);
    >     }
    >
    > }
    >
    > class StackImpl1 {
    >
    >     private Object[] stackArray;
    >     private volatile int topOfStack;
    >
    >     StackImpl1(int capacity) {
    >         stackArray = new Object[capacity];
    >         topOfStack = -1;
    >     }
    >
    >     public synchronized Object pop() {
    >         System.out.println(Thread.currentThread()
    >             + ": popping");
    >
    >         while (isEmpty()) {
    >             try {
    >                 System.out.println(Thread.currentThread()
    >                     + ": waiting to pop");
    >                 wait();
    >             } catch (InterruptedException e) {
    >             }
    >         }
    >         Object obj = stackArray[topOfStack];
    >         stackArray[topOfStack--] = null;
    >         System.out.println(Thread.currentThread()
    >             + ": notifying after pop");
    >         notify();
    >         return obj;
    >     }
    >
    >     public synchronized void push(Object element) {
    >         System.out.println(Thread.currentThread()
    >             + ": pushing");
    >         while (isFull()) {
    >             try {
    >                 System.out.println(Thread.currentThread()
    >                     + ": waiting to push");
    >                 wait();
    >             } catch (InterruptedException e) {
    >             }
    >         }
    >         stackArray[++topOfStack] = element;
    >         System.out.println(Thread.currentThread()
    >             + ": notifying after push");
    >         notify();
    >     }
    >
    >     public boolean isFull() {
    >         return topOfStack >= stackArray.length - 1;
    >     }
    >
    >     public boolean isEmpty() {
    >         return topOfStack < 0;
    >     }
    >
    > }
    >
    > abstract class StackUser extends Thread {
    >
    >     protected StackImpl1 stack;
    >
    >     StackUser(String threadName, StackImpl1 stack) {
    >         super(threadName);
    >         this.stack = stack;
    >         System.out.println(this);
    >         setDaemon(true);
    >         start();
    >     }
    >
    > }
    >
    > class StackPopper extends StackUser {
    >
    >     StackPopper(String threadName, StackImpl1 stack) {
    >         super(threadName, stack);
    >     }
    >
    >     public void run() {
    >         while (true) {
    >             stack.pop();
    >         }
    >     }
    >
    > }
    >
    > class StackPusher extends StackUser {
    >
    >     StackPusher(String threadName, StackImpl1 stack) {
    >         super(threadName, stack);
    >     }
    >
    >     public void run() {
    >         while (true) {
    >             stack.push(new Integer(1));
    >         }
    >     }}
    >
    > </sscce>
    >
    > --
    > John B. Matthews
    > trashgod at gmail dot comhttp://home.roadrunner.com/~jbmatthews/


    Sorry John, I did not understand completely what you were trying to
    say. Could you be a little more explicit with the explanation. Did you
    modify my program in some way ?
    --
    Ankur
     
    ankur, Dec 28, 2008
    #3
  4. In article
    <>,
    ankur <> wrote:

    > On Dec 27, 2:44 pm, "John B. Matthews" <> wrote:
    > > In article
    > > <>,
    > >
    > >  ankur <> wrote:
    > > > This code defines 3 threads A, B and C as Daemon threads. However
    > > > they continue to push and pop on the Stack even after the main thread
    > > > (user thread) has died. How is that possible ? Because Daemon threads
    > > > exist only so long as user threads exist..isn't it ?

    > > [...]
    > > I would say your program's execution is compliant. It just takes a
    > > little time for the VM to reap your doomed daemons; or you can
    > > foreclose explicitly, as shown in this nicely wrapped version
    > > of your example:
    > > [...]

    > Sorry John, I did not understand completely what you were trying to
    > say. Could you be a little more explicit with the explanation.


    <http://java.sun.com/docs/books/jls/third_edition/html/execution.html>

    See section 12.8; it's quite short. Your version terminates the first
    way; mine the second. I found it instructive to profile your version.

    > Did you modify my program in some way?


    Yes, as described in section 12.8, item 2. In addition, I reordered the
    class declarations and wrapped the listing to fit the column limit
    common to newsreaders. I did this so that others can try your code
    without repeating my effort, as my interpretation of your observations
    may benefit from correction or amplification.

    [Please trim sigs.]
    --
    John B. Matthews
    trashgod at gmail dot com
    http://home.roadrunner.com/~jbmatthews/
     
    John B. Matthews, Dec 28, 2008
    #4
  5. ankur

    ankur Guest

    On Dec 27, 4:45 pm, "John B. Matthews" <> wrote:
    > In article
    > <>,
    >
    >
    >
    >  ankur <> wrote:
    > > On Dec 27, 2:44 pm, "John B. Matthews" <> wrote:
    > > > In article
    > > > <>,

    >
    > > >  ankur <> wrote:
    > > > > This code defines 3 threads A, B and C as Daemon threads. However
    > > > > they continue to push and pop on the Stack even after the main thread
    > > > > (user thread) has died. How is that possible ? Because Daemon threads
    > > > > exist only so long as user threads exist..isn't it ?
    > > > [...]
    > > > I would say your program's execution is compliant. It just takes a
    > > > little time for the VM to reap your doomed daemons; or you can
    > > > foreclose explicitly, as shown in this nicely wrapped version
    > > > of your example:
    > > > [...]

    > > Sorry John, I did not understand completely what you were trying to
    > > say. Could you be a little more explicit with the explanation.

    >
    > <http://java.sun.com/docs/books/jls/third_edition/html/execution.html>
    >
    > See section 12.8; it's quite short. Your version terminates the first
    > way; mine the second. I found it instructive to profile your version.
    >
    > > Did you modify my program in some way?

    >
    > Yes, as described in section 12.8, item 2. In addition, I reordered the
    > class declarations and wrapped the listing to fit the column limit
    > common to newsreaders. I did this so that others can try your code
    > without repeating my effort, as my interpretation of your observations
    > may benefit from correction or amplification.
    >
    > [Please trim sigs.]
    > --
    > John B. Matthews
    > trashgod at gmail dot comhttp://home.roadrunner.com/~jbmatthews/


    Hi John,

    But I still did not understand why the threads A, B, C stay active
    even after the main thread has terminated and System.exit(1) has also
    been called!

    I think you mentioned something to this effect when you said : "It
    just takes a
    little time for the VM to reap your doomed daemons; ". Can you
    elaborate please ?

    Thanks,
    Ankur
     
    ankur, Dec 28, 2008
    #5
  6. ankur wrote:
    > I think you mentioned something to this effect when you said : "It
    > just takes a
    > little time for the VM to reap your doomed daemons; ". Can you
    > elaborate please ?


    After the main thread terminates, the VM takes some time to clean up the
    daemon threads; part of the thread destruction probably involves some GC
    runs (finalizers might verify this, but the nature of how finalizers are
    invoked could cause problems).

    The threads are, therefore, still running while the VM gets around to
    cleaning up all the rapidly-dying threads.

    --
    Beware of bugs in the above code; I have only proved it correct, not
    tried it. -- Donald E. Knuth
     
    Joshua Cranmer, Dec 28, 2008
    #6
  7. In article
    <>,
    ankur <> wrote:

    > On Dec 27, 4:45 pm, "John B. Matthews" <> wrote:
    > > In article
    > > <>,
    > >
    > >
    > >
    > >  ankur <> wrote:
    > > > On Dec 27, 2:44 pm, "John B. Matthews" <> wrote:
    > > > > In article
    > > > > <>,

    > >
    > > > >  ankur <> wrote:
    > > > > > This code defines 3 threads A, B and C as Daemon threads. However
    > > > > > they continue to push and pop on the Stack even after the main thread
    > > > > > (user thread) has died. How is that possible ? Because Daemon threads
    > > > > > exist only so long as user threads exist..isn't it ?
    > > > > [...]
    > > > > I would say your program's execution is compliant. It just takes a
    > > > > little time for the VM to reap your doomed daemons; or you can
    > > > > foreclose explicitly, as shown in this nicely wrapped version
    > > > > of your example:
    > > > > [...]
    > > > Sorry John, I did not understand completely what you were trying to
    > > > say. Could you be a little more explicit with the explanation.

    > >
    > > <http://java.sun.com/docs/books/jls/third_edition/html/execution.html>
    > >
    > > See section 12.8; it's quite short. Your version terminates the first
    > > way; mine the second. I found it instructive to profile your version.
    > >
    > > > Did you modify my program in some way?

    > >
    > > Yes, as described in section 12.8, item 2. In addition, I reordered the
    > > class declarations and wrapped the listing to fit the column limit
    > > common to newsreaders. I did this so that others can try your code
    > > without repeating my effort, as my interpretation of your observations
    > > may benefit from correction or amplification.


    [Please trim sigs.]

    > But I still did not understand why the threads A, B, C stay active
    > even after the main thread has terminated and System.exit(1) has also
    > been called!


    Well, when your non-daemon thread concludes execution, the daemon
    threads are still running. What does section 12.8 say happens next?

    > I think you mentioned something to this effect when you said : "It
    > just takes a little time for the VM to reap your doomed daemons; ".
    > Can you elaborate please?


    I don't know what else to say: Section 12.8 doesn't specify how it
    happens, only that it does, eventually. I presume that it takes some
    finite amount of time after the last line of main() executes, during
    which a number of pushes and pops occur.

    If I had to guess, based on the timeline, a thread named DestroyJavaVM
    starts waiting just about the time main() ends. What do you see when you
    profile your code?

    --
    John B. Matthews
    trashgod at gmail dot com
    http://home.roadrunner.com/~jbmatthews/
     
    John B. Matthews, Dec 28, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Franz Bayer

    CLDC - Daemon Thread

    Franz Bayer, Jul 29, 2004, in forum: Java
    Replies:
    1
    Views:
    385
    Darryl L. Pierce
    Aug 6, 2004
  2. adeon

    Daemon thread - strange??

    adeon, Apr 23, 2005, in forum: Java
    Replies:
    0
    Views:
    1,013
    adeon
    Apr 23, 2005
  3. Jean-Paul Calderone
    Replies:
    0
    Views:
    456
    Jean-Paul Calderone
    Mar 20, 2009
  4. Floris Bruynooghe
    Replies:
    1
    Views:
    453
    Floris Bruynooghe
    Mar 24, 2009
  5. Daemon Win32::Daemon;

    , Sep 7, 2006, in forum: Perl Misc
    Replies:
    0
    Views:
    255
Loading...

Share This Page