提交 800b483c 编写于 作者: C chegar

6576763: Thread constructors throw undocumented NPE for null name

Summary: update javadoc to specify NPE as well as fix minor bug in implementation.
Reviewed-by: alanb
上级 a86a5927
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -30,7 +30,6 @@ import java.security.AccessControlContext; ...@@ -30,7 +30,6 @@ import java.security.AccessControlContext;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.Map; import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
import java.util.Collections;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import sun.misc.SoftCache; import sun.misc.SoftCache;
import sun.nio.ch.Interruptible; import sun.nio.ch.Interruptible;
...@@ -120,6 +119,10 @@ import sun.security.util.SecurityConstants; ...@@ -120,6 +119,10 @@ import sun.security.util.SecurityConstants;
* Every thread has a name for identification purposes. More than * Every thread has a name for identification purposes. More than
* one thread may have the same name. If a name is not specified when * 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. * a thread is created, a new name is generated for it.
* <p>
* 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 * @author unascribed
* @see Runnable * @see Runnable
...@@ -348,6 +351,10 @@ class Thread implements Runnable { ...@@ -348,6 +351,10 @@ class Thread implements Runnable {
*/ */
private void init(ThreadGroup g, Runnable target, String name, private void init(ThreadGroup g, Runnable target, String name,
long stackSize) { long stackSize) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
Thread parent = currentThread(); Thread parent = currentThread();
SecurityManager security = System.getSecurityManager(); SecurityManager security = System.getSecurityManager();
if (g == null) { if (g == null) {
...@@ -379,7 +386,6 @@ class Thread implements Runnable { ...@@ -379,7 +386,6 @@ class Thread implements Runnable {
} }
} }
g.addUnstarted(); g.addUnstarted();
this.group = g; this.group = g;
...@@ -403,160 +409,175 @@ class Thread implements Runnable { ...@@ -403,160 +409,175 @@ class Thread implements Runnable {
tid = nextThreadID(); tid = nextThreadID();
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(null, null,</code> * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* <i>gname</i><code>)</code>, where <b><i>gname</i></b> is * {@code (null, null, gname)}, where {@code gname} is a newly generated
* a newly generated name. Automatically generated names are of the * name. Automatically generated names are of the form
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
*
* @see #Thread(ThreadGroup, Runnable, String)
*/ */
public Thread() { public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0); init(null, null, "Thread-" + nextThreadNum(), 0);
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(null, target,</code> * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* <i>gname</i><code>)</code>, where <i>gname</i> is * {@code (null, target, gname)}, where {@code gname} is a newly generated
* a newly generated name. Automatically generated names are of the * name. Automatically generated names are of the form
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
* *
* @param target the object whose <code>run</code> method is called. * @param target
* @see #Thread(ThreadGroup, Runnable, String) * 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) { public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0); init(null, target, "Thread-" + nextThreadNum(), 0);
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(group, target,</code> * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* <i>gname</i><code>)</code>, where <i>gname</i> is * {@code (group, target, gname)} ,where {@code gname} is a newly generated
* a newly generated name. Automatically generated names are of the * name. Automatically generated names are of the form
* form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
* *
* @param group the thread group. * @param group
* @param target the object whose <code>run</code> method is called. * the thread group. If {@code null} and there is a security
* @exception SecurityException if the current thread cannot create a * manager, the group is determined by {@linkplain
* thread in the specified thread group. * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* @see #Thread(ThreadGroup, Runnable, String) * 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) { public Thread(ThreadGroup group, Runnable target) {
init(group, target, "Thread-" + nextThreadNum(), 0); init(group, target, "Thread-" + nextThreadNum(), 0);
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(null, null, name)</code>. * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, null, name)}.
* *
* @param name the name of the new thread. * @param name
* @see #Thread(ThreadGroup, Runnable, String) * the name of the new thread
*/ */
public Thread(String name) { public Thread(String name) {
init(null, null, name, 0); init(null, null, name, 0);
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(group, null, name)</code> * 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
* @param name the name of the new thread. * the name of the new thread
* @exception SecurityException if the current thread cannot create a *
* thread in the specified thread group. * @throws SecurityException
* @see #Thread(ThreadGroup, Runnable, String) * if the current thread cannot create a thread in the specified
* thread group
*/ */
public Thread(ThreadGroup group, String name) { public Thread(ThreadGroup group, String name) {
init(group, null, name, 0); init(group, null, name, 0);
} }
/** /**
* Allocates a new <code>Thread</code> object. This constructor has * Allocates a new {@code Thread} object. This constructor has the same
* the same effect as <code>Thread(null, target, name)</code>. * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* {@code (null, target, name)}.
* *
* @param target the object whose <code>run</code> method is called. * @param target
* @param name the name of the new thread. * the object whose {@code run} method is invoked when this thread
* @see #Thread(ThreadGroup, Runnable, String) * 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) { public Thread(Runnable target, String name) {
init(null, target, name, 0); init(null, target, name, 0);
} }
/** /**
* Allocates a new <code>Thread</code> object so that it has * Allocates a new {@code Thread} object so that it has {@code target}
* <code>target</code> as its run object, has the specified * as its run object, has the specified {@code name} as its name,
* <code>name</code> as its name, and belongs to the thread group * and belongs to the thread group referred to by {@code group}.
* referred to by <code>group</code>. *
* <p> * <p>If there is a security manager, its
* If <code>group</code> is <code>null</code> and there is a * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
* security manager, the group is determined by the security manager's * method is invoked with the ThreadGroup as its argument.
* <code>getThreadGroup</code> method. If <code>group</code> is *
* <code>null</code> and there is not a security manager, or the * <p>In addition, its {@code checkPermission} method is invoked with
* security manager's <code>getThreadGroup</code> method returns * the {@code RuntimePermission("enableContextClassLoaderOverride")}
* <code>null</code>, the group is set to be the same ThreadGroup
* as the thread that is creating the new thread.
*
* <p>If there is a security manager, its <code>checkAccess</code>
* method is called with the ThreadGroup as its argument.
* <p>In addition, its <code>checkPermission</code>
* method is called with the
* <code>RuntimePermission("enableContextClassLoaderOverride")</code>
* permission when invoked directly or indirectly by the constructor * permission when invoked directly or indirectly by the constructor
* of a subclass which overrides the <code>getContextClassLoader</code> * of a subclass which overrides the {@code getContextClassLoader}
* or <code>setContextClassLoader</code> methods. * or {@code setContextClassLoader} methods.
* This may result in a SecurityException. *
* <p>The priority of the newly created thread is set equal to the
* <p>
* If the <code>target</code> argument is not <code>null</code>, the
* <code>run</code> method of the <code>target</code> is called when
* this thread is started. If the target argument is
* <code>null</code>, this thread's <code>run</code> method is called
* when this thread is started.
* <p>
* The priority of the newly created thread is set equal to the
* priority of the thread creating it, that is, the currently running * priority of the thread creating it, that is, the currently running
* thread. The method <code>setPriority</code> may be used to * thread. The method {@linkplain #setPriority setPriority} may be
* change the priority to a new value. * used to change the priority to a new value.
* <p> *
* The newly created thread is initially marked as being a daemon * <p>The newly created thread is initially marked as being a daemon
* thread if and only if the thread creating it is currently marked * thread if and only if the thread creating it is currently marked
* as a daemon thread. The method <code>setDaemon </code> may be used * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
* to change whether or not a thread is a daemon. * may be used to change whether or not a thread is a daemon.
* *
* @param group the thread group. * @param group
* @param target the object whose <code>run</code> method is called. * the thread group. If {@code null} and there is a security
* @param name the name of the new thread. * manager, the group is determined by {@linkplain
* @exception SecurityException if the current thread cannot create a * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* thread in the specified thread group or cannot * If there is not a security manager or {@code
* override the context class loader methods. * SecurityManager.getThreadGroup()} returns {@code null}, the group
* @see Runnable#run() * is set to the current thread's thread group.
* @see #run() *
* @see #setDaemon(boolean) * @param target
* @see #setPriority(int) * the object whose {@code run} method is invoked when this thread
* @see ThreadGroup#checkAccess() * is started. If {@code null}, this thread's run method is invoked.
* @see SecurityManager#checkAccess *
* @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) { public Thread(ThreadGroup group, Runnable target, String name) {
init(group, target, name, 0); init(group, target, name, 0);
} }
/** /**
* Allocates a new <code>Thread</code> object so that it has * Allocates a new {@code Thread} object so that it has {@code target}
* <code>target</code> as its run object, has the specified * as its run object, has the specified {@code name} as its name,
* <code>name</code> as its name, belongs to the thread group referred to * and belongs to the thread group referred to by {@code group}, and has
* by <code>group</code>, and has the specified <i>stack size</i>. * the specified <i>stack size</i>.
* *
* <p>This constructor is identical to {@link * <p>This constructor is identical to {@link
* #Thread(ThreadGroup,Runnable,String)} with the exception of the fact * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
* that it allows the thread stack size to be specified. The stack size * 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 * is the approximate number of bytes of address space that the virtual
* machine is to allocate for this thread's stack. <b>The effect of the * machine is to allocate for this thread's stack. <b>The effect of the
* <tt>stackSize</tt> parameter, if any, is highly platform dependent.</b> * {@code stackSize} parameter, if any, is highly platform dependent.</b>
* *
* <p>On some platforms, specifying a higher value for the * <p>On some platforms, specifying a higher value for the
* <tt>stackSize</tt> 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}. * recursion depth before throwing a {@link StackOverflowError}.
* Similarly, specifying a lower value may allow a greater number of * Similarly, specifying a lower value may allow a greater number of
* threads to exist concurrently without throwing an {@link * threads to exist concurrently without throwing an {@link
...@@ -564,9 +585,9 @@ class Thread implements Runnable { ...@@ -564,9 +585,9 @@ class Thread implements Runnable {
* the relationship between the value of the <tt>stackSize</tt> parameter * the relationship between the value of the <tt>stackSize</tt> parameter
* and the maximum recursion depth and concurrency level are * and the maximum recursion depth and concurrency level are
* platform-dependent. <b>On some platforms, the value of the * platform-dependent. <b>On some platforms, the value of the
* <tt>stackSize</tt> parameter may have no effect whatsoever.</b> * {@code stackSize} parameter may have no effect whatsoever.</b>
* *
* <p>The virtual machine is free to treat the <tt>stackSize</tt> * <p>The virtual machine is free to treat the {@code stackSize}
* parameter as a suggestion. If the specified value is unreasonably low * parameter as a suggestion. If the specified value is unreasonably low
* for the platform, the virtual machine may instead use some * for the platform, the virtual machine may instead use some
* platform-specific minimum value; if the specified value is unreasonably * platform-specific minimum value; if the specified value is unreasonably
...@@ -574,9 +595,9 @@ class Thread implements Runnable { ...@@ -574,9 +595,9 @@ class Thread implements Runnable {
* maximum. Likewise, the virtual machine is free to round the specified * maximum. Likewise, the virtual machine is free to round the specified
* value up or down as it sees fit (or to ignore it completely). * value up or down as it sees fit (or to ignore it completely).
* *
* <p>Specifying a value of zero for the <tt>stackSize</tt> parameter will * <p>Specifying a value of zero for the {@code stackSize} parameter will
* cause this constructor to behave exactly like the * cause this constructor to behave exactly like the
* <tt>Thread(ThreadGroup, Runnable, String)</tt> constructor. * {@code Thread(ThreadGroup, Runnable, String)} constructor.
* *
* <p><i>Due to the platform-dependent nature of the behavior of this * <p><i>Due to the platform-dependent nature of the behavior of this
* constructor, extreme care should be exercised in its use. * constructor, extreme care should be exercised in its use.
...@@ -588,15 +609,32 @@ class Thread implements Runnable { ...@@ -588,15 +609,32 @@ class Thread implements Runnable {
* *
* <p>Implementation note: Java platform implementers are encouraged to * <p>Implementation note: Java platform implementers are encouraged to
* document their implementation's behavior with respect to the * document their implementation's behavior with respect to the
* <tt>stackSize parameter</tt>. * {@code stackSize} parameter.
* *
* @param group the thread group. *
* @param target the object whose <code>run</code> method is called. * @param group
* @param name the name of the new thread. * the thread group. If {@code null} and there is a security
* @param stackSize the desired stack size for the new thread, or * manager, the group is determined by {@linkplain
* zero to indicate that this parameter is to be ignored. * SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
* @exception SecurityException if the current thread cannot create a * If there is not a security manager or {@code
* thread in the specified thread group. * 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 * @since 1.4
*/ */
public Thread(ThreadGroup group, Runnable target, String name, public Thread(ThreadGroup group, Runnable target, String name,
...@@ -669,6 +707,7 @@ class Thread implements Runnable { ...@@ -669,6 +707,7 @@ class Thread implements Runnable {
* @see #stop() * @see #stop()
* @see #Thread(ThreadGroup, Runnable, String) * @see #Thread(ThreadGroup, Runnable, String)
*/ */
@Override
public void run() { public void run() {
if (target != null) { if (target != null) {
target.run(); target.run();
...@@ -1386,28 +1425,25 @@ class Thread implements Runnable { ...@@ -1386,28 +1425,25 @@ class Thread implements Runnable {
* Returns the context ClassLoader for this Thread. The context * Returns the context ClassLoader for this Thread. The context
* ClassLoader is provided by the creator of the thread for use * ClassLoader is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources. * by code running in this thread when loading classes and resources.
* If not set, the default is the ClassLoader context of the parent * If not {@linkplain #setContextClassLoader set}, the default is the
* Thread. The context ClassLoader of the primordial thread is * ClassLoader context of the parent Thread. The context ClassLoader of the
* typically set to the class loader used to load the application. * primordial thread is typically set to the class loader used to load the
* * application.
* <p>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 * <p>If a security manager is present, and the invoker's class loader is not
* an ancestor of the context class loader for the thread whose * {@code null} and is not the same as or an ancestor of the context class
* context class loader is being requested, then the security manager's * loader, then this method invokes the security manager's {@link
* <code>checkPermission</code> * SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method is called with a * method with a {@link RuntimePermission RuntimePermission}{@code
* <code>RuntimePermission("getClassLoader")</code> permission * ("getClassLoader")} permission to verify that retrieval of the context
* to see if it's ok to get the context ClassLoader.. * 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 the current thread cannot get the context ClassLoader
* @throws SecurityException
* if a security manager exists and its
* <code>checkPermission</code> method doesn't allow
* getting the context ClassLoader.
* @see #setContextClassLoader
* @see SecurityManager#checkPermission
* @see RuntimePermission
* *
* @since 1.2 * @since 1.2
*/ */
...@@ -1428,21 +1464,22 @@ class Thread implements Runnable { ...@@ -1428,21 +1464,22 @@ class Thread implements Runnable {
/** /**
* Sets the context ClassLoader for this Thread. The context * Sets the context ClassLoader for this Thread. The context
* ClassLoader can be set when a thread is created, and allows * ClassLoader can be set when a thread is created, and allows
* the creator of the thread to provide the appropriate class loader * the creator of the thread to provide the appropriate class loader,
* to code running in the thread when loading classes and resources. * through {@code getContextClassLoader}, to code running in the thread
* when loading classes and resources.
* *
* <p>First, if there is a security manager, its <code>checkPermission</code> * <p>If a security manager is present, its {@link
* method is called with a * SecurityManager#checkPermission(java.security.Permission) checkPermission}
* <code>RuntimePermission("setContextClassLoader")</code> permission * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
* to see if it's ok to set the context ClassLoader.. * ("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 * @throws SecurityException
* context ClassLoader. * if the current thread cannot set the context ClassLoader
* @see #getContextClassLoader
* @see SecurityManager#checkPermission
* @see RuntimePermission
* *
* @since 1.2 * @since 1.2
*/ */
......
/*
* 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();
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册