diff --git a/src/share/classes/java/lang/Thread.java b/src/share/classes/java/lang/Thread.java index e6dd655b366518ea2fb373e237e29c7a3327e1d6..60300ebc911b8eceaa96911ff8d180c8cbf9e3d1 100644 --- a/src/share/classes/java/lang/Thread.java +++ b/src/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright 1994-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1994-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.security.AccessControlContext; import java.security.PrivilegedAction; import java.util.Map; import java.util.HashMap; -import java.util.Collections; import java.util.concurrent.locks.LockSupport; import sun.misc.SoftCache; import sun.nio.ch.Interruptible; @@ -120,6 +119,10 @@ import sun.security.util.SecurityConstants; * Every thread has a name for identification purposes. More than * one thread may have the same name. If a name is not specified when * a thread is created, a new name is generated for it. + *
+ * Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
*
* @author unascribed
* @see Runnable
@@ -348,6 +351,10 @@ class Thread implements Runnable {
*/
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
+ if (name == null) {
+ throw new NullPointerException("name cannot be null");
+ }
+
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
@@ -379,7 +386,6 @@ class Thread implements Runnable {
}
}
-
g.addUnstarted();
this.group = g;
@@ -403,160 +409,175 @@ class Thread implements Runnable {
tid = nextThreadID();
}
- /**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(null, null,
- * gname)
, where gname is
- * a newly generated name. Automatically generated names are of the
- * form "Thread-"+
n, where n is an integer.
- *
- * @see #Thread(ThreadGroup, Runnable, String)
+ /**
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (null, null, gname)}, where {@code gname} is a newly generated
+ * name. Automatically generated names are of the form
+ * {@code "Thread-"+}n, where n is an integer.
*/
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
/**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(null, target,
- * gname)
, where gname is
- * a newly generated name. Automatically generated names are of the
- * form "Thread-"+
n, where n is an integer.
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (null, target, gname)}, where {@code gname} is a newly generated
+ * name. Automatically generated names are of the form
+ * {@code "Thread-"+}n, where n is an integer.
*
- * @param target the object whose run
method is called.
- * @see #Thread(ThreadGroup, Runnable, String)
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this classes {@code run} method does
+ * nothing.
*/
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
/**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(group, target,
- * gname)
, where gname is
- * a newly generated name. Automatically generated names are of the
- * form "Thread-"+
n, where n is an integer.
- *
- * @param group the thread group.
- * @param target the object whose run
method is called.
- * @exception SecurityException if the current thread cannot create a
- * thread in the specified thread group.
- * @see #Thread(ThreadGroup, Runnable, String)
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (group, target, gname)} ,where {@code gname} is a newly generated
+ * name. Automatically generated names are of the form
+ * {@code "Thread-"+}n, where n is an integer.
+ *
+ * @param group
+ * the thread group. If {@code null} and there is a security
+ * manager, the group is determined by {@linkplain
+ * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+ * If there is not a security manager or {@code
+ * SecurityManager.getThreadGroup()} returns {@code null}, the group
+ * is set to the current thread's thread group.
+ *
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this thread's run method is invoked.
+ *
+ * @throws SecurityException
+ * if the current thread cannot create a thread in the specified
+ * thread group
*/
public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0);
}
/**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(null, null, name)
.
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (null, null, name)}.
*
- * @param name the name of the new thread.
- * @see #Thread(ThreadGroup, Runnable, String)
+ * @param name
+ * the name of the new thread
*/
public Thread(String name) {
init(null, null, name, 0);
}
/**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(group, null, name)
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (group, null, name)}.
+ *
+ * @param group
+ * the thread group. If {@code null} and there is a security
+ * manager, the group is determined by {@linkplain
+ * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+ * If there is not a security manager or {@code
+ * SecurityManager.getThreadGroup()} returns {@code null}, the group
+ * is set to the current thread's thread group.
*
- * @param group the thread group.
- * @param name the name of the new thread.
- * @exception SecurityException if the current thread cannot create a
- * thread in the specified thread group.
- * @see #Thread(ThreadGroup, Runnable, String)
+ * @param name
+ * the name of the new thread
+ *
+ * @throws SecurityException
+ * if the current thread cannot create a thread in the specified
+ * thread group
*/
public Thread(ThreadGroup group, String name) {
init(group, null, name, 0);
}
/**
- * Allocates a new Thread
object. This constructor has
- * the same effect as Thread(null, target, name)
.
+ * Allocates a new {@code Thread} object. This constructor has the same
+ * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+ * {@code (null, target, name)}.
*
- * @param target the object whose run
method is called.
- * @param name the name of the new thread.
- * @see #Thread(ThreadGroup, Runnable, String)
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this thread's run method is invoked.
+ *
+ * @param name
+ * the name of the new thread
*/
public Thread(Runnable target, String name) {
init(null, target, name, 0);
}
/**
- * Allocates a new Thread
object so that it has
- * target
as its run object, has the specified
- * name
as its name, and belongs to the thread group
- * referred to by group
.
- *
- * If group
is null
and there is a
- * security manager, the group is determined by the security manager's
- * getThreadGroup
method. If group
is
- * null
and there is not a security manager, or the
- * security manager's getThreadGroup
method returns
- * null
, the group is set to be the same ThreadGroup
- * as the thread that is creating the new thread.
- *
- *
If there is a security manager, its checkAccess
- * method is called with the ThreadGroup as its argument.
- *
In addition, its checkPermission
- * method is called with the
- * RuntimePermission("enableContextClassLoaderOverride")
+ * Allocates a new {@code Thread} object so that it has {@code target}
+ * as its run object, has the specified {@code name} as its name,
+ * and belongs to the thread group referred to by {@code group}.
+ *
+ *
If there is a security manager, its + * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess} + * method is invoked with the ThreadGroup as its argument. + * + *
In addition, its {@code checkPermission} method is invoked with
+ * the {@code RuntimePermission("enableContextClassLoaderOverride")}
* permission when invoked directly or indirectly by the constructor
- * of a subclass which overrides the getContextClassLoader
- * or setContextClassLoader
methods.
- * This may result in a SecurityException.
-
- *
- * If the target
argument is not null
, the
- * run
method of the target
is called when
- * this thread is started. If the target argument is
- * null
, this thread's run
method is called
- * when this thread is started.
- *
- * The priority of the newly created thread is set equal to the + * of a subclass which overrides the {@code getContextClassLoader} + * or {@code setContextClassLoader} methods. + * + *
The priority of the newly created thread is set equal to the
* priority of the thread creating it, that is, the currently running
- * thread. The method setPriority
may be used to
- * change the priority to a new value.
- *
- * The newly created thread is initially marked as being a daemon + * thread. The method {@linkplain #setPriority setPriority} may be + * used to change the priority to a new value. + * + *
The newly created thread is initially marked as being a daemon
* thread if and only if the thread creating it is currently marked
- * as a daemon thread. The method setDaemon
may be used
- * to change whether or not a thread is a daemon.
- *
- * @param group the thread group.
- * @param target the object whose run
method is called.
- * @param name the name of the new thread.
- * @exception SecurityException if the current thread cannot create a
- * thread in the specified thread group or cannot
- * override the context class loader methods.
- * @see Runnable#run()
- * @see #run()
- * @see #setDaemon(boolean)
- * @see #setPriority(int)
- * @see ThreadGroup#checkAccess()
- * @see SecurityManager#checkAccess
+ * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
+ * may be used to change whether or not a thread is a daemon.
+ *
+ * @param group
+ * the thread group. If {@code null} and there is a security
+ * manager, the group is determined by {@linkplain
+ * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+ * If there is not a security manager or {@code
+ * SecurityManager.getThreadGroup()} returns {@code null}, the group
+ * is set to the current thread's thread group.
+ *
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this thread's run method is invoked.
+ *
+ * @param name
+ * the name of the new thread
+ *
+ * @throws SecurityException
+ * if the current thread cannot create a thread in the specified
+ * thread group or cannot override the context class loader methods.
*/
public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0);
}
/**
- * Allocates a new Thread
object so that it has
- * target
as its run object, has the specified
- * name
as its name, belongs to the thread group referred to
- * by group
, and has the specified stack size.
+ * Allocates a new {@code Thread} object so that it has {@code target}
+ * as its run object, has the specified {@code name} as its name,
+ * and belongs to the thread group referred to by {@code group}, and has
+ * the specified stack size.
*
*
This constructor is identical to {@link * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact * that it allows the thread stack size to be specified. The stack size * is the approximate number of bytes of address space that the virtual * machine is to allocate for this thread's stack. The effect of the - * stackSize parameter, if any, is highly platform dependent. + * {@code stackSize} parameter, if any, is highly platform dependent. * *
On some platforms, specifying a higher value for the - * stackSize parameter may allow a thread to achieve greater + * {@code stackSize} parameter may allow a thread to achieve greater * recursion depth before throwing a {@link StackOverflowError}. * Similarly, specifying a lower value may allow a greater number of * threads to exist concurrently without throwing an {@link @@ -564,9 +585,9 @@ class Thread implements Runnable { * the relationship between the value of the stackSize parameter * and the maximum recursion depth and concurrency level are * platform-dependent. On some platforms, the value of the - * stackSize parameter may have no effect whatsoever. + * {@code stackSize} parameter may have no effect whatsoever. * - *
The virtual machine is free to treat the stackSize + *
The virtual machine is free to treat the {@code stackSize} * parameter as a suggestion. If the specified value is unreasonably low * for the platform, the virtual machine may instead use some * platform-specific minimum value; if the specified value is unreasonably @@ -574,9 +595,9 @@ class Thread implements Runnable { * maximum. Likewise, the virtual machine is free to round the specified * value up or down as it sees fit (or to ignore it completely). * - *
Specifying a value of zero for the stackSize parameter will + *
Specifying a value of zero for the {@code stackSize} parameter will * cause this constructor to behave exactly like the - * Thread(ThreadGroup, Runnable, String) constructor. + * {@code Thread(ThreadGroup, Runnable, String)} constructor. * *
Due to the platform-dependent nature of the behavior of this * constructor, extreme care should be exercised in its use. @@ -588,15 +609,32 @@ class Thread implements Runnable { * *
Implementation note: Java platform implementers are encouraged to
* document their implementation's behavior with respect to the
- * stackSize parameter.
- *
- * @param group the thread group.
- * @param target the object whose run
method is called.
- * @param name the name of the new thread.
- * @param stackSize the desired stack size for the new thread, or
- * zero to indicate that this parameter is to be ignored.
- * @exception SecurityException if the current thread cannot create a
- * thread in the specified thread group.
+ * {@code stackSize} parameter.
+ *
+ *
+ * @param group
+ * the thread group. If {@code null} and there is a security
+ * manager, the group is determined by {@linkplain
+ * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+ * If there is not a security manager or {@code
+ * SecurityManager.getThreadGroup()} returns {@code null}, the group
+ * is set to the current thread's thread group.
+ *
+ * @param target
+ * the object whose {@code run} method is invoked when this thread
+ * is started. If {@code null}, this thread's run method is invoked.
+ *
+ * @param name
+ * the name of the new thread
+ *
+ * @param stackSize
+ * the desired stack size for the new thread, or zero to indicate
+ * that this parameter is to be ignored.
+ *
+ * @throws SecurityException
+ * if the current thread cannot create a thread in the specified
+ * thread group
+ *
* @since 1.4
*/
public Thread(ThreadGroup group, Runnable target, String name,
@@ -669,6 +707,7 @@ class Thread implements Runnable {
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
+ @Override
public void run() {
if (target != null) {
target.run();
@@ -1386,28 +1425,25 @@ class Thread implements Runnable {
* Returns the context ClassLoader for this Thread. The context
* ClassLoader is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources.
- * If not set, the default is the ClassLoader context of the parent
- * Thread. The context ClassLoader of the primordial thread is
- * typically set to the class loader used to load the application.
- *
- *
First, if there is a security manager, and the caller's class
- * loader is not null and the caller's class loader is not the same as or
- * an ancestor of the context class loader for the thread whose
- * context class loader is being requested, then the security manager's
- * checkPermission
- * method is called with a
- * RuntimePermission("getClassLoader")
permission
- * to see if it's ok to get the context ClassLoader..
+ * If not {@linkplain #setContextClassLoader set}, the default is the
+ * ClassLoader context of the parent Thread. The context ClassLoader of the
+ * primordial thread is typically set to the class loader used to load the
+ * application.
+ *
+ *
If a security manager is present, and the invoker's class loader is not
+ * {@code null} and is not the same as or an ancestor of the context class
+ * loader, then this method invokes the security manager's {@link
+ * SecurityManager#checkPermission(java.security.Permission) checkPermission}
+ * method with a {@link RuntimePermission RuntimePermission}{@code
+ * ("getClassLoader")} permission to verify that retrieval of the context
+ * class loader is permitted.
+ *
+ * @return the context ClassLoader for this Thread, or {@code null}
+ * indicating the system class loader (or, failing that, the
+ * bootstrap class loader)
*
- * @return the context ClassLoader for this Thread
- *
- * @throws SecurityException
- * if a security manager exists and its
- * checkPermission
method doesn't allow
- * getting the context ClassLoader.
- * @see #setContextClassLoader
- * @see SecurityManager#checkPermission
- * @see RuntimePermission
+ * @throws SecurityException
+ * if the current thread cannot get the context ClassLoader
*
* @since 1.2
*/
@@ -1428,21 +1464,22 @@ class Thread implements Runnable {
/**
* Sets the context ClassLoader for this Thread. The context
* ClassLoader can be set when a thread is created, and allows
- * the creator of the thread to provide the appropriate class loader
- * to code running in the thread when loading classes and resources.
+ * the creator of the thread to provide the appropriate class loader,
+ * through {@code getContextClassLoader}, to code running in the thread
+ * when loading classes and resources.
*
- *
First, if there is a security manager, its checkPermission
- * method is called with a
- * RuntimePermission("setContextClassLoader")
permission
- * to see if it's ok to set the context ClassLoader..
+ *
If a security manager is present, its {@link + * SecurityManager#checkPermission(java.security.Permission) checkPermission} + * method is invoked with a {@link RuntimePermission RuntimePermission}{@code + * ("setContextClassLoader")} permission to see if setting the context + * ClassLoader is permitted. * - * @param cl the context ClassLoader for this Thread + * @param cl + * the context ClassLoader for this Thread, or null indicating the + * system class loader (or, failing that, the bootstrap class loader) * - * @exception SecurityException if the current thread cannot set the - * context ClassLoader. - * @see #getContextClassLoader - * @see SecurityManager#checkPermission - * @see RuntimePermission + * @throws SecurityException + * if the current thread cannot set the context ClassLoader * * @since 1.2 */ diff --git a/test/java/lang/ThreadGroup/NullThreadName.java b/test/java/lang/ThreadGroup/NullThreadName.java new file mode 100644 index 0000000000000000000000000000000000000000..844fd93e2d815903b4994540027c76c95d0711cc --- /dev/null +++ b/test/java/lang/ThreadGroup/NullThreadName.java @@ -0,0 +1,85 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6576763 + * @summary (thread) Thread constructors throw undocumented NPE for null name + */ + +/* + * Verify that threads constructed with a null thread name do not get added + * to the list of unstarted thread for a thread group. We can do this by + * checking that a daemon threadGroup is desroyed after its final valid thread + * has completed. + */ + +import java.util.concurrent.CountDownLatch; +import static java.lang.System.out; + +public class NullThreadName +{ + static CountDownLatch done = new CountDownLatch(1); + + public static void main(String args[]) throws Exception { + ThreadGroup tg = new ThreadGroup("chegar-threads"); + Thread goodThread = new Thread(tg, new GoodThread(), "goodThread"); + try { + Thread badThread = new Thread(tg, new Runnable(){ + @Override + public void run() {} }, null); + } catch (NullPointerException npe) { + out.println("OK, caught expected " + npe); + } + tg.setDaemon(true); + goodThread.start(); + + done.await(); + + int count = 0; + while (goodThread.isAlive()) { + /* Hold off a little to allow the thread to complete */ + out.println("GoodThread still alive, sleeping..."); + try { Thread.sleep(2000); } + catch (InterruptedException unused) {} + + /* do not wait forever */ + if (count++ > 5) + throw new AssertionError("GoodThread is still alive!"); + } + + if (!tg.isDestroyed()) { + throw new AssertionError("Failed: Thread group is not destroyed."); + } + } + + static class GoodThread implements Runnable + { + @Override + public void run() { + out.println("Good Thread started..."); + out.println("Good Thread finishing"); + done.countDown(); + } + } +}