JDK-4494726 : (thread) ThreadGroup.enumerate() does not return all active threads
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.0,1.4.1
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_98,windows_2000
  • CPU: x86
  • Submitted: 2001-08-21
  • Updated: 2007-04-18
  • Resolved: 2007-04-18
Related Reports
Relates :  
Description

Name: nt126004			Date: 08/21/2001


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

I use ThreadGroup.activeCount() to get the number of active threads.
Then use ThreadGroup.enumerate(Thread[]) to copy all active threads into Thread
[] , but i find that ThreadGroup.enumerate(Thread[]) only copy the first thread
into Thread[].  The result of activeCount() is always 2, however enumerate only
finds one Thread.
please see the source code (from Thinking in JAVA by Bruce Eckel) and the
result below:

=====================
//:TestAccess.java
//How threads can access other threads
//in a parent thread group
public class TestAccess {
  public static void main(String[] args){
        ThreadGroup
        x =new ThreadGroup("x"),
        y =new ThreadGroup(x,"y"),
        z =new ThreadGroup(y,"z");
        Thread
        one =new TestThread1(x,"one"),
        two =new TestThread2(z,"two");
  }
}

class TestThread1 extends Thread {
private int i;
TestThread1(ThreadGroup g,String name){
super(g,name);
}
void f(){
i++; //modify this thread
System.out.println(getName()+" f()");
}
}                  
class TestThread2 extends TestThread1 {
TestThread2(ThreadGroup g,String name){
super(g,name);
start();
}
public void run(){
ThreadGroup g=getThreadGroup().getParent().getParent();
g.list();
System.out.println("ThreadCount: "+g.activeCount());
Thread[] gAll =new Thread[g.activeCount()];
g.enumerate(gAll);
System.out.println("ThreadCount: "+gAll.length);
for(int i=0; i<gAll.length;i++){
System.out.println(i+" - ");
gAll[i].setPriority(Thread.MIN_PRIORITY);
((TestThread1)gAll[i]).f();
}
g.list();
}
}
=====================
output:

java.lang.ThreadGroup[name=x,maxpri=10]
    Thread[one,5,x]
    java.lang.ThreadGroup[name=y,maxpri=10]
        java.lang.ThreadGroup[name=z,maxpri=10]
            Thread[two,5,z]
ThreadCount: 2
ThreadCount: 2
0 -
two f()
1 -
java.lang.NullPointerException
        at TestThread2.run(TestAccess.java:44)
(Review ID: 130375) 
======================================================================

Name: nt126004			Date: 04/09/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)


FULL OPERATING SYSTEM VERSION :
Windows 98 [Version 4.10.2222]


A DESCRIPTION OF THE PROBLEM :
According to Oaks & Wong, "Java Threads, 2nd", p. 33-34,
Thread.enumerate() should return a list containing
Thread.activeCount() objects of type Thread, even if those
objects have no other references, and that such objects
are those which have been constructed and neither exited
from their run() method nor been stopped.

The evidence of the enclosed program shows a different
behavior; activeCount() will report as expected, but
enumerate() fails to return Thread objects with no (other)
references.

The API is silent on all this, as usual.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the sample program.
2.
3.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected and actual results are noted in the code sample.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class Test extends Thread {
	public Test(String s) {
		super(s);	// save our name
	}
	public static void main(String[] args) {
		{	// (intentional extra block)
			int ac = Thread.activeCount();
			System.out.println(ac);	// prints 2
			Thread[] ta = new Thread[10];
			for(int i=0;i<10;++i) {
				String str = "thread"+i;
				ta[i] = new Test(str);	// (a thread)
				System.out.println("created "+ta[i].getName());
					// just to be sure
			}
			ac = Thread.activeCount();
				// i.e., constructed but not exited or stopped
				// (according to Oaks & Wong)
			System.out.println(ac);	// prints 12 (expected)
		}	// intentional loss of scope
		int ac = Thread.activeCount();
		System.out.println(ac);	// prints 12 (expected - threads were
				// constructed and not run-exited or stopped)
		Thread tb[] = new Thread[ac];
		int n = Thread.enumerate(tb);	// should get all those
				// constructed threads
		System.out.println(n);	//prints 1 (unexpected; if activeCount()
			// returned 12, enumerate() should give us 12 also)
		for(int i=0;i<n;++i) {
			System.out.println(tb[i].getName());
                        // only prints "main"
			if(!tb[i].isAlive()) {
                              // i.e., run() has not been called
				System.out.println("starting "+i);
                                     // never executes
				tb[i].start();	// exits immediately (see below)
			}
		}
		try {
			Thread.sleep(5000);
                         // maybe we need time for threads to vanish
		}
		catch (InterruptedException ex) {
		}
		ac = Thread.activeCount();
		System.out.println(ac);
                   // prints 12 (expected only if they haven't run)
	}
	public void run() {
		System.out.println("thread started");
	}
}

---------- END SOURCE ----------
(Review ID: 144715)
======================================================================

Comments
EVALUATION Class TestThread1 lacks a run method, so its using Thread.run and because no Runnable was specified Thread.run immediately returns, causing the thread to immediately terminate. The ThreadGroup.enumerate method only counts alive threads, a detail currently missing from this method's documentation, but this distinction is why the 2nd thread is never "seen" by enumerate (but it might theoretically be seen occasionally, depending on random OS scheduler behavior if TestThread1 were to be pended by the OS while inside it's "empty" run method). (The term "active thread" is used without pointing out that in this context what is meant is "alive thread"). This doc defect will be corrected by CR 4109242.
18-04-2007