Index: java/lang/Thread.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/lang/Thread.java,v retrieving revision 1.2 diff -u -b -B -r1.2 Thread.java --- java/lang/Thread.java 21 Nov 2003 08:08:00 -0000 1.2 +++ java/lang/Thread.java 28 Jan 2004 19:37:34 -0000 @@ -1,5 +1,6 @@ /* Thread -- an independent thread of executable code - Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation This file is part of GNU Classpath. @@ -37,6 +38,14 @@ package java.lang; +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete to version 1.4, with caveats. We do not + * implement the deprecated (and dangerous) stop, suspend, and resume + * methods. Security implementation is not complete. + */ + /** * Thread represents a single thread of execution in the VM. When an * application VM starts up, it creates a non-daemon Thread which calls the @@ -65,6 +74,7 @@ * or interrupted? The only thing that is clear is that the Thread should be * removed when it is stopped. * + * @author Tom Tromey * @author John Keiser * @author Eric Blake * @see Runnable @@ -310,6 +320,51 @@ } /** + * Get the number of active threads in the current Thread's ThreadGroup. + * This implementation calls + * currentThread().getThreadGroup().activeCount(). + * + * @return the number of active threads in the current ThreadGroup + * @see ThreadGroup#activeCount() + */ + public static int activeCount() + { + return currentThread().group.activeCount(); + } + + /** + * Check whether the current Thread is allowed to modify this Thread. This + * passes the check on to SecurityManager.checkAccess(this). + * + * @throws SecurityException if the current Thread cannot modify this Thread + * @see SecurityManager#checkAccess(Thread) + */ + public final void checkAccess() + { + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = Runtime.securityManager; + if (sm != null) + sm.checkAccess(this); + } + + /** + * Count the number of stack frames in this Thread. The Thread in question + * must be suspended when this occurs. + * + * @return the number of stack frames in this Thread + * @throws IllegalThreadStateException if this Thread is not suspended + * @deprecated pointless, since suspend is deprecated + */ + public int countStackFrames() + { + VMThread t = vmThread; + if (t == null || group == null) + throw new IllegalThreadStateException(); + + return t.countStackFrames(); + } + + /** * Get the currently executing Thread. In the situation that the * currently running thread was created by native code and doesn't * have an associated Thread object yet, a new Thread object is @@ -323,162 +378,88 @@ } /** - * Yield to another thread. The Thread will not lose any locks it holds - * during this time. There are no guarantees which thread will be - * next to run, and it could even be this one, but most VMs will choose - * the highest priority thread that has been waiting longest. + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. */ - public static void yield() + public void destroy() { - VMThread.yield(); } /** - * Suspend the current Thread's execution for the specified amount of - * time. The Thread will not lose any locks it has during this time. There - * are no guarantees which thread will be next to run, but most VMs will - * choose the highest priority thread that has been waiting longest. + * Print a stack trace of the current thread to stderr using the same + * format as Throwable's printStackTrace() method. * - * @param ms the number of milliseconds to sleep, or 0 for forever - * @throws InterruptedException if the Thread is interrupted; it's - * interrupted status will be cleared - * @see #notify() - * @see #wait(long) + * @see Throwable#printStackTrace() */ - public static void sleep(long ms) throws InterruptedException + public static void dumpStack() { - sleep(ms, 0); + new Throwable().printStackTrace(); } /** - * Suspend the current Thread's execution for the specified amount of - * time. The Thread will not lose any locks it has during this time. There - * are no guarantees which thread will be next to run, but most VMs will - * choose the highest priority thread that has been waiting longest. - * - *

Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do - * not offer that fine a grain of timing resolution. Besides, there is - * no guarantee that this thread can start up immediately when time expires, - * because some other thread may be active. So don't expect real-time - * performance. + * Copy every active thread in the current Thread's ThreadGroup into the + * array. Extra threads are silently ignored. This implementation calls + * getThreadGroup().enumerate(array), which may have a + * security check, checkAccess(group). * - * @param ms the number of milliseconds to sleep, or 0 for forever - * @param ns the number of extra nanoseconds to sleep (0-999999) - * @throws InterruptedException if the Thread is interrupted; it's - * interrupted status will be cleared - * @throws IllegalArgumentException if ns is invalid - * @see #notify() - * @see #wait(long, int) + * @param array the array to place the Threads into + * @return the number of Threads placed into the array + * @throws NullPointerException if array is null + * @throws SecurityException if you cannot access the ThreadGroup + * @see ThreadGroup#enumerate(Thread[]) + * @see #activeCount() + * @see SecurityManager#checkAccess(ThreadGroup) */ - public static void sleep(long ms, int ns) throws InterruptedException + public static int enumerate(Thread[] array) { - VMThread.sleep(ms, ns); + return currentThread().group.enumerate(array); } /** - * Start this Thread, calling the run() method of the Runnable this Thread - * was created with, or else the run() method of the Thread itself. This - * is the only way to start a new thread; calling run by yourself will just - * stay in the same thread. The virtual machine will remove the thread from - * its thread group when the run() method completes. + * Get this Thread's name. * - * @throws IllegalThreadStateException if the thread has already started - * @see #run() + * @return this Thread's name */ - public synchronized void start() + public final String getName() { - if (vmThread != null || group == null) - throw new IllegalThreadStateException(); - - VMThread.create(this, stacksize); + VMThread t = vmThread; + return t == null ? name : t.getName(); } /** - * The method of Thread that will be run if there is no Runnable object - * associated with the Thread. Thread's implementation does nothing at all. + * Get this Thread's priority. * - * @see #start() - * @see #Thread(ThreadGroup, Runnable, String) + * @return the Thread's priority */ - public void run() + public final synchronized int getPriority() { - if (toRun != null) - toRun.run(); + VMThread t = vmThread; + return t == null ? priority : t.getPriority(); } /** - * Cause this Thread to stop abnormally because of the throw of a ThreadDeath - * error. If you stop a Thread that has not yet started, it will stop - * immediately when it is actually started. - * - *

This is inherently unsafe, as it can interrupt synchronized blocks and - * leave data in bad states. Hence, there is a security check: - * checkAccess(this), plus another one if the current thread - * is not this: RuntimePermission("stopThread"). If you must - * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. - * ThreadDeath is the only exception which does not print a stack trace when - * the thread dies. + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. * - * @throws SecurityException if you cannot stop the Thread - * @see #interrupt() - * @see #checkAccess() - * @see #start() - * @see ThreadDeath - * @see ThreadGroup#uncaughtException(Thread, Throwable) - * @see SecurityManager#checkAccess(Thread) - * @see SecurityManager#checkPermission(Permission) - * @deprecated unsafe operation, try not to use + * @return this Thread's ThreadGroup */ - public final void stop() + public final ThreadGroup getThreadGroup() { - stop(new ThreadDeath()); + return group; } /** - * Cause this Thread to stop abnormally and throw the specified exception. - * If you stop a Thread that has not yet started, the stop is ignored - * (contrary to what the JDK documentation says). - * WARNINGThis bypasses Java security, and can throw a checked - * exception which the call stack is unprepared to handle. Do not abuse - * this power. - * - *

This is inherently unsafe, as it can interrupt synchronized blocks and - * leave data in bad states. Hence, there is a security check: - * checkAccess(this), plus another one if the current thread - * is not this: RuntimePermission("stopThread"). If you must - * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. - * ThreadDeath is the only exception which does not print a stack trace when - * the thread dies. + * Checks whether the current thread holds the monitor on a given object. + * This allows you to do assert Thread.holdsLock(obj). * - * @param t the Throwable to throw when the Thread dies - * @throws SecurityException if you cannot stop the Thread - * @throws NullPointerException in the calling thread, if t is null - * @see #interrupt() - * @see #checkAccess() - * @see #start() - * @see ThreadDeath - * @see ThreadGroup#uncaughtException(Thread, Throwable) - * @see SecurityManager#checkAccess(Thread) - * @see SecurityManager#checkPermission(Permission) - * @deprecated unsafe operation, try not to use + * @param obj the object to check + * @return true if the current thread is currently synchronized on obj + * @throws NullPointerException if obj is null + * @since 1.4 */ - public final synchronized void stop(Throwable t) - { - if (t == null) - throw new NullPointerException(); - // Bypass System.getSecurityManager, for bootstrap efficiency. - SecurityManager sm = Runtime.securityManager; - if (sm != null) + public static boolean holdsLock(Object obj) { - sm.checkAccess(this); - if (this != currentThread()) - sm.checkPermission(new RuntimePermission("stopThread")); - } - VMThread vt = vmThread; - if (vt != null) - vt.stop(t); - else - stillborn = t; + return VMThread.holdsLock(obj); } /** @@ -537,14 +518,6 @@ } /** - * Originally intended to destroy this thread, this method was never - * implemented by Sun, and is hence a no-op. - */ - public void destroy() - { - } - - /** * Determine whether this Thread is alive. A thread which is alive has * started and not yet died. * @@ -556,188 +529,213 @@ } /** - * Suspend this Thread. It will not come back, ever, unless it is resumed. - * - *

This is inherently unsafe, as the suspended thread still holds locks, - * and can potentially deadlock your program. Hence, there is a security - * check: checkAccess. + * Tell whether this is a daemon Thread or not. * - * @throws SecurityException if you cannot suspend the Thread - * @see #checkAccess() - * @see #resume() - * @deprecated unsafe operation, try not to use + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) */ - public final synchronized void suspend() + public final boolean isDaemon() { - checkAccess(); VMThread t = vmThread; - if (t != null) - t.suspend(); + return t == null ? daemon : t.isDaemon(); } /** - * Resume this Thread. If the thread is not suspended, this method does - * nothing. To mirror suspend(), there may be a security check: - * checkAccess. + * Wait forever for the Thread in question to die. * - * @throws SecurityException if you cannot resume the Thread - * @see #checkAccess() - * @see #suspend() - * @deprecated pointless, since suspend is deprecated + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared */ - public final synchronized void resume() + public final void join() throws InterruptedException { - checkAccess(); - VMThread t = vmThread; - if (t != null) - t.resume(); + join(0, 0); } /** - * Set this Thread's priority. There may be a security check, - * checkAccess, then the priority is set to the smaller of - * priority and the ThreadGroup maximum priority. + * Wait the specified amount of time for the Thread in question to die. * - * @param priority the new priority for this Thread - * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or - * MAX_PRIORITY - * @throws SecurityException if you cannot modify this Thread - * @see #getPriority() - * @see #checkAccess() - * @see ThreadGroup#getMaxPriority() - * @see #MIN_PRIORITY - * @see #MAX_PRIORITY + * @param ms the number of milliseconds to wait, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared */ - public final synchronized void setPriority(int priority) + public final void join(long ms) throws InterruptedException { - checkAccess(); - if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) - throw new IllegalArgumentException("Invalid thread priority value " - + priority + "."); - priority = Math.min(priority, group.getMaxPriority()); - VMThread t = vmThread; - if (t != null) - t.setPriority(priority); - else - this.priority = priority; + join(ms, 0); } /** - * Get this Thread's priority. + * Wait the specified amount of time for the Thread in question to die. * - * @return the Thread's priority + *

Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + * @throws IllegalArgumentException if ns is invalid */ - public final synchronized int getPriority() + public final void join(long ms, int ns) throws InterruptedException { + if(ms < 0 || ns < 0 || ns > 999999) + throw new IllegalArgumentException(); + VMThread t = vmThread; - return t == null ? priority : t.getPriority(); + if(t != null) + t.join(ms, ns); } /** - * Set this Thread's name. There may be a security check, + * Resume this Thread. If the thread is not suspended, this method does + * nothing. To mirror suspend(), there may be a security check: * checkAccess. * - * @param name the new name for this Thread - * @throws NullPointerException if name is null - * @throws SecurityException if you cannot modify this Thread + * @throws SecurityException if you cannot resume the Thread + * @see #checkAccess() + * @see #suspend() + * @deprecated pointless, since suspend is deprecated */ - public final synchronized void setName(String name) + public final synchronized void resume() { checkAccess(); - // Use toString hack to detect null. - name = name.toString(); VMThread t = vmThread; if (t != null) - t.setName(name); - else - this.name = name; + t.resume(); } /** - * Get this Thread's name. + * The method of Thread that will be run if there is no Runnable object + * associated with the Thread. Thread's implementation does nothing at all. * - * @return this Thread's name + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) */ - public final String getName() + public void run() { - VMThread t = vmThread; - return t == null ? name : t.getName(); + if (toRun != null) + toRun.run(); } /** - * Get the ThreadGroup this Thread belongs to. If the thread has died, this - * returns null. + * Set the daemon status of this Thread. If this is a daemon Thread, then + * the VM may exit even if it is still running. This may only be called + * while the Thread is not running. There may be a security check, + * checkAccess. * - * @return this Thread's ThreadGroup + * @param daemon whether this should be a daemon thread or not + * @throws SecurityException if you cannot modify this Thread + * @throws IllegalThreadStateException if the Thread is active + * @see #isDaemon() + * @see #checkAccess() */ - public final ThreadGroup getThreadGroup() + public final synchronized void setDaemon(boolean daemon) { - return group; + if (vmThread != null || group == null) + throw new IllegalThreadStateException(); + checkAccess(); + this.daemon = daemon; } /** - * Get the number of active threads in the current Thread's ThreadGroup. - * This implementation calls - * currentThread().getThreadGroup().activeCount(). + * Returns the context classloader of this Thread. The context + * classloader can be used by code that want to load classes depending + * on the current thread. Normally classes are loaded depending on + * the classloader of the current class. There may be a security check + * for RuntimePermission("getClassLoader") if the caller's + * class loader is not null or an ancestor of this thread's context class + * loader. * - * @return the number of active threads in the current ThreadGroup - * @see ThreadGroup#activeCount() + * @return the context class loader + * @throws SecurityException when permission is denied + * @see setContextClassLoader(ClassLoader) + * @since 1.2 */ - public static int activeCount() + public ClassLoader getContextClassLoader() { - return currentThread().group.activeCount(); + // Bypass System.getSecurityManager, for bootstrap efficiency. + SecurityManager sm = Runtime.securityManager; + if (sm != null) + // XXX Don't check this if the caller's class loader is an ancestor. + sm.checkPermission(new RuntimePermission("getClassLoader")); + return contextClassLoader; } /** - * Copy every active thread in the current Thread's ThreadGroup into the - * array. Extra threads are silently ignored. This implementation calls - * getThreadGroup().enumerate(array), which may have a - * security check, checkAccess(group). + * Sets the context classloader for this Thread. When not explicitly set, + * the context classloader for a thread is the same as the context + * classloader of the thread that created this thread. The first thread has + * as context classloader the system classloader. There may be a security + * check for RuntimePermission("setContextClassLoader"). * - * @param array the array to place the Threads into - * @return the number of Threads placed into the array - * @throws NullPointerException if array is null - * @throws SecurityException if you cannot access the ThreadGroup - * @see ThreadGroup#enumerate(Thread[]) - * @see #activeCount() - * @see SecurityManager#checkAccess(ThreadGroup) + * @param classloader the new context class loader + * @throws SecurityException when permission is denied + * @see getContextClassLoader() + * @since 1.2 */ - public static int enumerate(Thread[] array) + public void setContextClassLoader(ClassLoader classloader) { - return currentThread().group.enumerate(array); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + this.contextClassLoader = classloader; } /** - * Count the number of stack frames in this Thread. The Thread in question - * must be suspended when this occurs. + * Set this Thread's name. There may be a security check, + * checkAccess. * - * @return the number of stack frames in this Thread - * @throws IllegalThreadStateException if this Thread is not suspended - * @deprecated pointless, since suspend is deprecated + * @param name the new name for this Thread + * @throws NullPointerException if name is null + * @throws SecurityException if you cannot modify this Thread */ - public int countStackFrames() + public final synchronized void setName(String name) { + checkAccess(); + // Use toString hack to detect null. + name = name.toString(); VMThread t = vmThread; - if (t == null || group == null) - throw new IllegalThreadStateException(); + if (t != null) + t.setName(name); + else + this.name = name; + } - return t.countStackFrames(); + /** + * Yield to another thread. The Thread will not lose any locks it holds + * during this time. There are no guarantees which thread will be + * next to run, and it could even be this one, but most VMs will choose + * the highest priority thread that has been waiting longest. + */ + public static void yield() + { + VMThread.yield(); } /** - * Wait the specified amount of time for the Thread in question to die. + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. * - * @param ms the number of milliseconds to wait, or 0 for forever + * @param ms the number of milliseconds to sleep, or 0 for forever * @throws InterruptedException if the Thread is interrupted; it's * interrupted status will be cleared + * @see #notify() + * @see #wait(long) */ - public final void join(long ms) throws InterruptedException + public static void sleep(long ms) throws InterruptedException { - join(ms, 0); + sleep(ms, 0); } /** - * Wait the specified amount of time for the Thread in question to die. + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. * *

Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do * not offer that fine a grain of timing resolution. Besides, there is @@ -745,162 +743,174 @@ * because some other thread may be active. So don't expect real-time * performance. * - * @param ms the number of milliseconds to wait, or 0 for forever + * @param ms the number of milliseconds to sleep, or 0 for forever * @param ns the number of extra nanoseconds to sleep (0-999999) * @throws InterruptedException if the Thread is interrupted; it's * interrupted status will be cleared * @throws IllegalArgumentException if ns is invalid + * @see #notify() + * @see #wait(long, int) */ - public final void join(long ms, int ns) throws InterruptedException + public static void sleep(long ms, int ns) throws InterruptedException { - if(ms < 0 || ns < 0 || ns > 999999) - throw new IllegalArgumentException(); - - VMThread t = vmThread; - if(t != null) - t.join(ms, ns); + VMThread.sleep(ms, ns); } /** - * Wait forever for the Thread in question to die. + * Start this Thread, calling the run() method of the Runnable this Thread + * was created with, or else the run() method of the Thread itself. This + * is the only way to start a new thread; calling run by yourself will just + * stay in the same thread. The virtual machine will remove the thread from + * its thread group when the run() method completes. * - * @throws InterruptedException if the Thread is interrupted; it's - * interrupted status will be cleared + * @throws IllegalThreadStateException if the thread has already started + * @see #run() */ - public final void join() throws InterruptedException + public synchronized void start() { - join(0, 0); - } + if (vmThread != null || group == null) + throw new IllegalThreadStateException(); - /** - * Print a stack trace of the current thread to stderr using the same - * format as Throwable's printStackTrace() method. - * - * @see Throwable#printStackTrace() - */ - public static void dumpStack() - { - new Throwable().printStackTrace(); + VMThread.create(this, stacksize); } /** - * Set the daemon status of this Thread. If this is a daemon Thread, then - * the VM may exit even if it is still running. This may only be called - * while the Thread is not running. There may be a security check, - * checkAccess. + * Cause this Thread to stop abnormally because of the throw of a ThreadDeath + * error. If you stop a Thread that has not yet started, it will stop + * immediately when it is actually started. * - * @param daemon whether this should be a daemon thread or not - * @throws SecurityException if you cannot modify this Thread - * @throws IllegalThreadStateException if the Thread is active - * @see #isDaemon() + *

This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @throws SecurityException if you cannot stop the Thread + * @see #interrupt() * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use */ - public final synchronized void setDaemon(boolean daemon) + public final void stop() { - if (vmThread != null || group == null) - throw new IllegalThreadStateException(); - checkAccess(); - this.daemon = daemon; + stop(new ThreadDeath()); } /** - * Tell whether this is a daemon Thread or not. + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, the stop is ignored + * (contrary to what the JDK documentation says). + * WARNINGThis bypasses Java security, and can throw a checked + * exception which the call stack is unprepared to handle. Do not abuse + * this power. * - * @return whether this is a daemon Thread or not - * @see #setDaemon(boolean) - */ - public final boolean isDaemon() - { - VMThread t = vmThread; - return t == null ? daemon : t.isDaemon(); - } - - /** - * Check whether the current Thread is allowed to modify this Thread. This - * passes the check on to SecurityManager.checkAccess(this). + *

This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * checkAccess(this), plus another one if the current thread + * is not this: RuntimePermission("stopThread"). If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. * - * @throws SecurityException if the current Thread cannot modify this Thread + * @param t the Throwable to throw when the Thread dies + * @throws SecurityException if you cannot stop the Thread + * @throws NullPointerException in the calling thread, if t is null + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use */ - public final void checkAccess() + public final synchronized void stop(Throwable t) { + if (t == null) + throw new NullPointerException(); // Bypass System.getSecurityManager, for bootstrap efficiency. SecurityManager sm = Runtime.securityManager; if (sm != null) + { sm.checkAccess(this); + if (this != currentThread()) + sm.checkPermission(new RuntimePermission("stopThread")); } - - /** - * Return a human-readable String representing this Thread. The format of - * the string is:
- * "Thread[" + getName() + ',' + getPriority() + ',' - * + (getThreadGroup() == null ? "" : getThreadGroup().getName()) - + ']'. - * - * @return a human-readable String representing this Thread - */ - public String toString() - { - return "Thread[" + name + ',' + priority + ',' - + (group == null ? "" : group.name) + ']'; + VMThread vt = vmThread; + if (vt != null) + vt.stop(t); + else + stillborn = t; } /** - * Returns the context classloader of this Thread. The context - * classloader can be used by code that want to load classes depending - * on the current thread. Normally classes are loaded depending on - * the classloader of the current class. There may be a security check - * for RuntimePermission("getClassLoader") if the caller's - * class loader is not null or an ancestor of this thread's context class - * loader. + * Suspend this Thread. It will not come back, ever, unless it is resumed. * - * @return the context class loader - * @throws SecurityException when permission is denied - * @see setContextClassLoader(ClassLoader) - * @since 1.2 + *

This is inherently unsafe, as the suspended thread still holds locks, + * and can potentially deadlock your program. Hence, there is a security + * check: checkAccess. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use */ - public ClassLoader getContextClassLoader() + public final synchronized void suspend() { - // Bypass System.getSecurityManager, for bootstrap efficiency. - SecurityManager sm = Runtime.securityManager; - if (sm != null) - // XXX Don't check this if the caller's class loader is an ancestor. - sm.checkPermission(new RuntimePermission("getClassLoader")); - return contextClassLoader; + checkAccess(); + VMThread t = vmThread; + if (t != null) + t.suspend(); } /** - * Sets the context classloader for this Thread. When not explicitly set, - * the context classloader for a thread is the same as the context - * classloader of the thread that created this thread. The first thread has - * as context classloader the system classloader. There may be a security - * check for RuntimePermission("setContextClassLoader"). + * Set this Thread's priority. There may be a security check, + * checkAccess, then the priority is set to the smaller of + * priority and the ThreadGroup maximum priority. * - * @param classloader the new context class loader - * @throws SecurityException when permission is denied - * @see getContextClassLoader() - * @since 1.2 + * @param priority the new priority for this Thread + * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or + * MAX_PRIORITY + * @throws SecurityException if you cannot modify this Thread + * @see #getPriority() + * @see #checkAccess() + * @see ThreadGroup#getMaxPriority() + * @see #MIN_PRIORITY + * @see #MAX_PRIORITY */ - public void setContextClassLoader(ClassLoader classloader) + public final synchronized void setPriority(int priority) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkPermission(new RuntimePermission("setContextClassLoader")); - this.contextClassLoader = classloader; + checkAccess(); + if (priority < MIN_PRIORITY || priority > MAX_PRIORITY) + throw new IllegalArgumentException("Invalid thread priority value " + + priority + "."); + priority = Math.min(priority, group.getMaxPriority()); + VMThread t = vmThread; + if (t != null) + t.setPriority(priority); + else + this.priority = priority; } /** - * Checks whether the current thread holds the monitor on a given object. - * This allows you to do assert Thread.holdsLock(obj). + * Return a human-readable String representing this Thread. The format of + * the string is:
+ * "Thread[" + getName() + ',' + getPriority() + ',' + * + (getThreadGroup() == null ? "" : getThreadGroup().getName()) + + ']'. * - * @param obj the object to check - * @return true if the current thread is currently synchronized on obj - * @throws NullPointerException if obj is null - * @since 1.4 + * @return a human-readable String representing this Thread */ - public static boolean holdsLock(Object obj) + public String toString() { - return VMThread.holdsLock(obj); + return ("Thread[" + name + "," + priority + "," + + (group == null ? "" : group.getName()) + "]"); } /** @@ -911,4 +921,4 @@ group.removeThread(this); vmThread = null; } -} // class Thread +}