From 514e19c9fb0aaa8d4c5a78b4b357b4c19bc8c7b4 Mon Sep 17 00:00:00 2001 From: Anthony Green Date: Sat, 22 Feb 2003 14:16:29 +0000 Subject: [PATCH] New docs for Thread.java, and little tweaks identified by japi. From-SVN: r63284 --- libjava/ChangeLog | 8 + libjava/java/lang/Class.java | 4 +- libjava/java/lang/Thread.java | 564 +++++++++++++++++++++++++++++++++- 3 files changed, 562 insertions(+), 14 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index da27b23f0b9..c35bdf2bdb0 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,11 @@ +2002-02-21 Anthony Green + + * java/lang/Thread.java (Thread): New constructor taking stack + size parameter (ignored for now). + * Many methods: Merged GNU Classpath documentation. + + * java/lang/Class.java (finalize): throws a Throwable. + 2003-02-21 Mark Wielaard * java/util/zip/ZipEntry.java (setComment): Don't check length when diff --git a/libjava/java/lang/Class.java b/libjava/java/lang/Class.java index cc1cc40f2a4..44f5b5ab529 100644 --- a/libjava/java/lang/Class.java +++ b/libjava/java/lang/Class.java @@ -1,6 +1,6 @@ // Class.java - Representation of a Java class. -/* Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -346,7 +346,7 @@ public final class Class implements Serializable private native void initializeClass (); // finalization - protected native void finalize (); + protected native void finalize () throws Throwable; /** * Strip the last portion of the name (after the last dot). diff --git a/libjava/java/lang/Thread.java b/libjava/java/lang/Thread.java index 18af8292126..33b0f450fa5 100644 --- a/libjava/java/lang/Thread.java +++ b/libjava/java/lang/Thread.java @@ -1,6 +1,6 @@ // Thread.java - Thread class. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -12,30 +12,84 @@ package java.lang; import gnu.gcj.RawData; -/** - * @author Tom Tromey - * @date August 24, 1998 - */ - /* 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.3, with caveats. We do not + * 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 + * main() method of a particular class. There may be other Threads running, + * such as the garbage collection thread. + * + *

Threads have names to identify them. These names are not necessarily + * unique. Every Thread has a priority, as well, which tells the VM which + * Threads should get more running time. New threads inherit the priority + * and daemon status of the parent thread, by default. + * + *

There are two methods of creating a Thread: you may subclass Thread and + * implement the run() method, at which point you may start the + * Thread by calling its start() method, or you may implement + * Runnable in the class you want to use and then call new + * Thread(your_obj).start(). + * + *

The virtual machine runs until all non-daemon threads have died (either + * by returning from the run() method as invoked by start(), or by throwing + * an uncaught exception); or until System.exit is called with + * adequate permissions. + * + *

It is unclear at what point a Thread should be added to a ThreadGroup, + * and at what point it should be removed. Should it be inserted when it + * starts, or when it is created? Should it be removed when it is suspended + * 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 + * @see Runtime#exit(int) + * @see #run() + * @see #start() + * @see ThreadLocal + * @since 1.0 + * @status updated to 1.4 + */ public class Thread implements Runnable { + /** The maximum priority for a Thread. */ public final static int MAX_PRIORITY = 10; + + /** The minimum priority for a Thread. */ public final static int MIN_PRIORITY = 1; + + /** The priority a Thread gets by default. */ public final static int NORM_PRIORITY = 5; + /** + * 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().getThreadGroup().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 () { SecurityManager s = System.getSecurityManager(); @@ -43,78 +97,218 @@ public class Thread implements Runnable s.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 native int countStackFrames (); + + /** + * Get the currently executing Thread. + * + * @return the currently executing Thread + */ public static native Thread currentThread (); + + /** + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. + */ public native void destroy (); + /** + * 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 Exception ("Stack trace")).printStackTrace (); } + /** + * 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 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 int enumerate (Thread[] threads) { return currentThread().group.enumerate(threads); } - + + /** + * Get this Thread's name. + * + * @return this Thread's name + */ public final String getName () { return name; } + /** + * Get this Thread's priority. + * + * @return the Thread's priority + */ public final int getPriority () { return priority; } + /** + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. + * + * @return this Thread's ThreadGroup + */ public final ThreadGroup getThreadGroup () { return group; } + /** + * Interrupt this Thread. First, there is a security check, + * checkAccess. Then, depending on the current state of the + * thread, various actions take place: + * + *

If the thread is waiting because of {@link #wait()}, + * {@link #sleep(long)}, or {@link #join()}, its interrupt status + * will be cleared, and an InterruptedException will be thrown. Notice that + * this case is only possible if an external thread called interrupt(). + * + *

If the thread is blocked in an interruptible I/O operation, in + * {@link java.nio.channels.InterruptibleChannel}, the interrupt + * status will be set, and ClosedByInterruptException will be thrown. + * + *

If the thread is blocked on a {@link java.nio.channels.Selector}, the + * interrupt status will be set, and the selection will return, with + * a possible non-zero value, as though by the wakeup() method. + * + *

Otherwise, the interrupt status will be set. + * + * @throws SecurityException if you cannot modify this Thread + */ public native void interrupt (); + /** + * Determine whether the current Thread has been interrupted, and clear + * the interrupted status in the process. + * + * @return whether the current Thread has been interrupted + * @see #isInterrupted() + */ public static boolean interrupted () { return currentThread().isInterrupted (true); } - // Check the threads interrupted status. Note that this does not clear the - // thread's interrupted status (per JDK 1.2 online API documentation). + /** + * Determine whether the given Thread has been interrupted, but leave + * the interrupted status alone in the process. + * + * @return whether the current Thread has been interrupted + * @see #interrupted() + */ public boolean isInterrupted () { return interrupt_flag; } + /** + * Determine whether this Thread is alive. A thread which is alive has + * started and not yet died. + * + * @return whether this Thread is alive + */ public final boolean isAlive () { return alive_flag; } + /** + * Tell whether this is a daemon Thread or not. + * + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) + */ public final boolean isDaemon () { return daemon_flag; } + /** + * Wait forever for the Thread in question to die. + * + * @throws InterruptedException if the Thread is interrupted; it's + * interrupted status will be cleared + */ public final void join () throws InterruptedException { join (0, 0); } + /** + * Wait the specified amount of time for the Thread in question to die. + * + * @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 void join (long timeout) throws InterruptedException { join (timeout, 0); } + /** + * Wait the specified amount of time for the Thread in question to die. + * + *

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 + * @XXX A ThreadListener would be nice, to make this efficient. + */ public final native void join (long timeout, int nanos) throws InterruptedException; + /** + * Resume a suspended thread. + * + * @see #resume() + */ public final native void resume (); private final native void finish_ (); - // Check the thread's interrupted status. If clear_flag is true, the - // thread's interrupted status is also cleared. + /** + * Determine whether the given Thread has been interrupted, but leave + * the interrupted status alone in the process. + * + * @return whether the current Thread has been interrupted + * @see #interrupted() + */ private boolean isInterrupted (boolean clear_flag) { boolean r = interrupt_flag; @@ -128,12 +322,31 @@ public class Thread implements Runnable return r; } + /** + * 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. + * + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) + */ public void run () { if (runnable != null) runnable.run(); } + /** + * 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 + * before the Thread starts running. There may be a security check, + * checkAccess. + * + * @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 void setDaemon (boolean status) { checkAccess (); @@ -142,6 +355,20 @@ public class Thread implements Runnable daemon_flag = status; } + /** + * 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 context class loader + * @throws SecurityException when permission is denied + * @see setContextClassLoader(ClassLoader) + * @since 1.2 + */ public synchronized ClassLoader getContextClassLoader() { if (context_class_loader == null) @@ -168,6 +395,20 @@ public class Thread implements Runnable return context_class_loader; } + /** + * 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 context class loader + * @throws SecurityException when permission is denied + * @see setContextClassLoader(ClassLoader) + * @since 1.2 + */ public synchronized void setContextClassLoader(ClassLoader cl) { SecurityManager s = System.getSecurityManager (); @@ -176,6 +417,14 @@ public class Thread implements Runnable context_class_loader = cl; } + /** + * Set this Thread's name. 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 + */ public final void setName (String n) { checkAccess (); @@ -186,17 +435,98 @@ public class Thread implements Runnable name = n; } + /** + * 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 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 final native void setPriority (int newPriority); + /** + * 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 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 static void sleep (long timeout) throws InterruptedException { sleep (timeout, 0); } + /** + * 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. + * + * @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 static native void sleep (long timeout, int nanos) throws InterruptedException; + + /** + * 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 IllegalThreadStateException if the thread has already started + * @see #run() + */ public native void start (); + /** + * 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. + * + * @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 void stop () { // Argument doesn't matter, because this is no longer @@ -204,13 +534,82 @@ public class Thread implements Runnable stop (null); } + /** + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, it will stop immediately + * when it is actually started. 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. + * + * @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 native void stop (Throwable e); + + /** + * 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. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use + */ public final native void suspend (); private final native void initialize_native (); private final native static String gen_name (); + /** + * Allocate a new Thread object, with the specified ThreadGroup and name, and + * using the specified Runnable object's run() method to + * execute. If the Runnable object is null, this (which is + * a Runnable) is used instead. + * + *

If the ThreadGroup is null, the security manager is checked. If a + * manager exists and returns a non-null object for + * getThreadGroup, that group is used; otherwise the group + * of the creating thread is used. Note that the security manager calls + * checkAccess if the ThreadGroup is not null. + * + *

The new Thread will inherit its creator's priority and daemon status. + * These can be changed with setPriority and + * setDaemon. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @see Runnable#run() + * @see #run() + * @see #setDaemon(boolean) + * @see #setPriority(int) + * @see SecurityManager#checkAccess(ThreadGroup) + * @see ThreadGroup#checkAccess() + */ public Thread (ThreadGroup g, Runnable r, String n) { this (currentThread (), g, r, n); @@ -221,6 +620,37 @@ public class Thread implements Runnable throw new NullPointerException (); } + /** + * Allocate a new Thread object, as if by + * Thread(group, null, name), and give it the specified stack + * size, in bytes. The stack size is highly platform independent, + * and the virtual machine is free to round up or down, or ignore it + * completely. A higher value might let you go longer before a + * StackOverflowError, while a lower value might let you go + * longer before an OutOfMemoryError. Or, it may do absolutely + * nothing! So be careful, and expect to need to tune this value if your + * virtual machine even supports it. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @param size the stack size, in bytes; 0 to be ignored + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access group + * @throws IllegalThreadStateException if group is destroyed + * @since 1.4 + */ + public Thread (ThreadGroup g, Runnable r, String n, long size) + { + // Just ignore stackSize for now. + this (currentThread (), g, r, n); + + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (n == null) + throw new NullPointerException (); + } + private Thread (Thread current, ThreadGroup g, Runnable r, String n) { if (g == null) @@ -264,42 +694,152 @@ public class Thread implements Runnable initialize_native (); } + /** + * 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. + *

+ * Threads created this way must have overridden their + * run() method to actually do anything. An example + * illustrating this method being used follows: + *

+   *     import java.lang.*;
+   *
+   *     class plain01 implements Runnable {
+   *         String name;
+   *         plain01() {
+   *             name = null;
+   *         }
+   *         plain01(String s) {
+   *             name = s;
+   *         }
+   *         public void run() {
+   *             if (name == null)
+   *                 System.out.println("A new thread created");
+   *             else
+   *                 System.out.println("A new thread with name " + name +
+   *                                    " created");
+   *         }
+   *     }
+   *     class threadtest01 {
+   *         public static void main(String args[] ) {
+   *             int failed = 0 ;
+   *
+   *             Thread t1 = new Thread();
+   *             if (t1 != null)
+   *                 System.out.println("new Thread() succeed");
+   *             else {
+   *                 System.out.println("new Thread() failed");
+   *                 failed++;
+   *             }
+   *         }
+   *     }
+   * 
+ * + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread () { this (null, null, gen_name ()); } + /** + * 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. + * + * @param target the object whose run method is called. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread (Runnable r) { this (null, r, gen_name ()); } + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, null, name). + * + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread (String n) { this (null, null, n); } + /** + * 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 java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread (ThreadGroup g, Runnable r) { this (g, r, gen_name ()); } + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(group, null, name) + * + * @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 java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread (ThreadGroup g, String n) { this (g, null, n); } + /** + * Allocates a new Thread object. This constructor has + * the same effect as Thread(null, target, name). + * + * @param target the object whose run method is called. + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ public Thread (Runnable r, String n) { this (null, r, n); } + /** + * Returns a string representation of this thread, including the + * thread's name, priority, and thread group. + * + * @return a string representation of this thread. + */ public String toString () { return "Thread[" + name + "," + priority + "," + (group == null ? "" : group.getName()) + "]"; } + /** + * Causes the currently executing thread object to temporarily pause + * and allow other threads to execute. + */ public static native void yield (); // Private data.