/* * @(#)Thread.java 1.50 96/03/06 * * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software * and its documentation for NON-COMMERCIAL purposes and without * fee is hereby granted provided that this copyright notice * appears in all copies. Please refer to the file "copyright.html" * for further important copyright and licensing information. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. */ package java.lang; /** * A Thread is a single sequential flow of control within a process. This simply means * that while executing within a program, each thread has a beginning, a sequence, a * point of execution occurring at any time during runtime of the thread and of course, an ending. * Thread objects are the basis for multi-threaded programming. Multi-threaded programming * allows a single program to conduct concurrently running threads that perform different tasks. *

* To create a new thread of execution, declare a new class which is a * subclass of Thread and then override the run() method with code that you * want executed in this Thread. An instance of the Thread subclass should be created next * with a call to the start() method following the instance. The start() method will create the * thread and execute the run() method. * For example:

*

 *	class PrimeThread extends Thread {
 *	    public void run() {
 *		// compute primes...
 *	    }
 *	}
 * 
* To start this thread you need to do the following: *
 *	PrimeThread p = new PrimeThread();
 *	p.start();
 *	...
 * 
* Another way to create a thread is by using the Runnable interface. * This way any object that implements the Runnable interface can be * run in a thread. For example: *
 *	class Primes implements Runnable {
 *	    public void run() {
 *		// compute primes...
 *	    }
 *	}
 * 
* To start this thread you need to do the following: *
 *	Primes p = new Primes();
 *	new Thread(p).start();
 *	...
 * 
* The virtual machine runs until all Threads that are not daemon Threads * have died. A Thread dies when its run() method returns, or when the * stop() method is called. *

* When a new Thread is created, it inherits the priority and the * daemon flag from its parent (i.e.: the Thread that created it). * @see Runnable * @version 1.50, 06 Mar 1996 */ public class Thread implements Runnable { private char name[]; private int priority; private Thread threadQ; private int PrivateInfo; private int eetop; /* Whether or not to single_step this thread. */ private boolean single_step; /* Whether or not the thread is a daemon thread. */ private boolean daemon = false; /* Whether or not this thread was asked to exit before it runs.*/ private boolean stillborn = false; /* What will be run. */ private Runnable target; /* Indicator of whether this thread has been interrupted */ private boolean interruptRequested = false; /* The system queue of threads is linked through activeThreadQueue. */ private static Thread activeThreadQ; /* The group of this thread */ private ThreadGroup group; /* For autonumbering anonymous threads. */ private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; } /** * The minimum priority that a Thread can have. The most minimal priority is equal to 1. */ public final static int MIN_PRIORITY = 1; /** * The default priority that is assigned to a Thread. The default priority is equal to 5. */ public final static int NORM_PRIORITY = 5; /** * The maximum priority that a Thread can have. The maximal priority value a Thread can have is 10. */ public final static int MAX_PRIORITY = 10; /** * Returns a reference to the currently executing Thread object. */ public static native Thread currentThread(); /** * Causes the currently executing Thread object to yield. * If there are other runnable Threads they will be * scheduled next. */ public static native void yield(); /** * Causes the currently executing Thread to sleep for the specified * number of milliseconds. * @param millis the length of time to sleep in milliseconds * @exception InterruptedException * Another thread has interrupted this thread. */ public static native void sleep(long millis) throws InterruptedException; /** * Sleep, in milliseconds and additional nanosecond. * @param millis the length of time to sleep in milliseconds * @param nanos 0-999999 additional nanoseconds to sleep * @exception InterruptedException * Another thread has interrupted this thread. */ public static void sleep(long millis, int nanos) throws InterruptedException { if (nanos > 500000) millis++; sleep(millis); } /** * Initialize a Thread. * @param g the Thread group * @param target the object whose run() method gets called * @param name the name of the new Thread */ private void init(ThreadGroup g, Runnable target, String name){ Thread parent = currentThread(); if (g == null) { g = parent.getThreadGroup(); } else { g.checkAccess(); } this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); this.name = name.toCharArray(); this.target = target; setPriority0(priority); g.add(this); } /** * Constructs a new Thread. Threads created this way must have * overridden their run() method to actually do anything. An example * illustrating this method being used is shown. *

     * 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++; * }

* }

*/ public Thread() { init(null, null, "Thread-" + nextThreadNum()); } /** * Constructs a new Thread which applies the run() method of * the specified target. * @param target the object whose run() method is called */ public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum()); } /** * Constructs a new Thread in the specified Thread group that applies the run() method of * the specified target. * @param group the Thread group * @param target the object whose run() method is called */ public Thread(ThreadGroup group, Runnable target) { init(group, target, "Thread-" + nextThreadNum()); } /** * Constructs a new Thread with the specified name. * @param name the name of the new Thread */ public Thread(String name) { init(null, null, name); } /** * Constructs a new Thread in the specified Thread group with the specified name. * @param group the Thread group * @param name the name of the new Thread */ public Thread(ThreadGroup group, String name) { init(group, null, name); } /** * Constructs a new Thread with the specified name and applies * the run() method of the specified target. * @param target the object whose run() method is called * @param name the name of the new Thread */ public Thread(Runnable target, String name) { init(null, target, name); } /** * Constructs a new Thread in the specified Thread group with the specified name and * applies the run() method of the specified target. * @param group the Thread group * @param target the object whose run() method is called * @param name the name of the new Thread */ public Thread(ThreadGroup group, Runnable target, String name) { init(group, target, name); } /** * Starts this Thread. This will cause the run() method to * be called. This method will return immediately. * @exception IllegalThreadStateException If the thread was already started. * @see Thread#run * @see Thread#stop */ public synchronized native void start(); /** * The actual body of this Thread. This method is called after * the Thread is started. You must either override this * method by subclassing class Thread, or you must create * the Thread with a Runnable target. * @see Thread#start * @see Thread#stop */ public void run() { if (target != null) { target.run(); } } /** * This method is called by the system to give a Thread * a chance to clean up before it actually exits. */ private void exit() { if (group != null) { group.remove(this); group = null; } } /** * Stops a Thread by tossing an object. By default this * routine tosses a new instance of ThreadDeath to the target * Thread. ThreadDeath is not actually a subclass of Exception, * but is a subclass of Object. Users should not normally try * to catch ThreadDeath unless they must do some extraordinary * cleanup operation. If ThreadDeath is caught it is important * to rethrow the object so that the thread will actually die. * The top-level error handler will not print out a message if * ThreadDeath falls through. * * @see Thread#start * @see Thread#run */ public final void stop() { stop(new ThreadDeath()); } /** * Stops a Thread by tossing an object. Normally, users should * just call the stop() method without any argument. However, in some * exceptional circumstances used by the stop() method to kill a Thread, * another object is tossed. ThreadDeath, is not actually a subclass * of Exception, but is a subclass of Throwable * @param o the Throwable object to be thrown * @see Thread#start * @see Thread#run */ public final synchronized void stop(Throwable o) { checkAccess(); stop0(o); } /** * Send an interrupt to a thread. */ public void interrupt() { // Note that this method is not syncronized. Three reasons for this: // 1) It changes the API // 2) It's another place where the system could hang. // 3) All we're doing is turning on a one-way bit. It doesn't matter // exactly when it's done wrt probes via the interrupted() function. interruptRequested = true; } /** * Ask if you have been interrupted. */ public static boolean interrupted() { // REMIND: this is only an 90% solution // In particular, none of the methods which should throw // InterruptedException() currently support that yet. return currentThread().interruptRequested; } /** * Ask if another thread has been interrupted. */ public boolean isInterrupted() { return interruptRequested; } /** * Destroy a thread, without any cleanup, i.e. just toss its state; * any monitors it has locked remain locked. A last resort. */ public void destroy() { throw new NoSuchMethodError(); } /** * Returns a boolean indicating if the Thread is active. Having an * active Thread means that the Thread has been started and has not * been stopped. */ public final native boolean isAlive(); /** * Suspends this Thread's execution. */ public final void suspend() { checkAccess(); suspend0(); } /** * Resumes this Thread execution. This method is only valid after suspend() * has been invoked. */ public final void resume() { checkAccess(); resume0(); } /** * Sets the Thread's priority. * @exception IllegalArgumentException If the priority is not within the * range MIN_PRIORITY, MAX_PRIORITY. * @see Thread#MIN_PRIORITY * @see Thread#MAX_PRIORITY * @see Thread#getPriority */ public final void setPriority(int newPriority) { checkAccess(); if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) { throw new IllegalArgumentException(); } if (newPriority > group.getMaxPriority()) { newPriority = group.getMaxPriority(); } setPriority0(priority = newPriority); } /** * Gets and returns the Thread's priority. * @see Thread#setPriority */ public final int getPriority() { return priority; } /** * Sets the Thread's name. * @param name the new name of the Thread * @see Thread#getName */ public final void setName(String name) { checkAccess(); this.name = name.toCharArray(); } /** * Gets and returns this Thread's name. * @see Thread#setName */ public final String getName() { return String.valueOf(name); } /** * Gets and returns this Thread group. */ public final ThreadGroup getThreadGroup() { return group; } /** * Returns the current number of active Threads in this Thread group. */ public static int activeCount() { return currentThread().getThreadGroup().activeCount(); } /** * Copies, into the specified array, references to every active Thread in this * Thread's group. * @return the number of Threads put into the array. */ public static int enumerate(Thread tarray[]) { return currentThread().getThreadGroup().enumerate(tarray); } /** * Returns the number of stack frames in this Thread. The Thread * must be suspended when this method is called. * @exception IllegalThreadStateException If the Thread is not suspended. */ public native int countStackFrames(); /** * Waits for this Thread to die. A timeout in milliseconds can * be specified. A timeout of 0 milliseconds means to wait * forever. * @param millis the time to wait in milliseconds * @exception InterruptedException * Another thread has interrupted this thread. */ public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } } /** * Waits for the Thread to die, with more precise time. * @exception InterruptedException * Another thread has interrupted this thread. */ public final synchronized void join(long millis, int nanos) throws InterruptedException { if (nanos >= 500000 || millis == 0) millis++; join(millis); } /** * Waits forever for this Thread to die. * @exception InterruptedException * Another thread has interrupted this thread. */ public final void join() throws InterruptedException { join(0); } /** * A debugging procedure to print a stack trace for the * current Thread. * @see Throwable#printStackTrace */ public static void dumpStack() { new Exception("Stack trace").printStackTrace(); } /** * Marks this Thread as a daemon Thread or a user Thread. * When there are only daemon Threads left running in the * system, Java exits. * @param on determines whether the Thread will be a daemon Thread * @exception IllegalThreadStateException If the Thread is active. * @see Thread#isDaemon */ public final void setDaemon(boolean on) { checkAccess(); if (isAlive()) { throw new IllegalThreadStateException(); } daemon = on; } /** * Returns the daemon flag of the Thread. * @see Thread#setDaemon */ public final boolean isDaemon() { return daemon; } /** * Checks whether the current Thread is allowed to modify this Thread. * @exception SecurityException If the current Thread is not allowed * to access this Thread group. */ public void checkAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkAccess(this); } } /** * Returns a String representation of the Thread, including the * thread's name, priority and thread group. */ public String toString() { return "Thread[" + getName() + "," + getPriority() + "," + getThreadGroup().getName() + "]"; } /* Some private helper methods */ private native void setPriority0(int newPriority); private native void stop0(Object o); private native void suspend0(); private native void resume0(); }