home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1997 October
/
Chip_1997-10_cd.bin
/
tema
/
sybase
/
powerj
/
java.z
/
Thread.java
< prev
next >
Wrap
Text File
|
1996-05-03
|
18KB
|
588 lines
/*
* @(#)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.
* <p>
* 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:<p>
* <pre>
* class PrimeThread extends Thread {
* public void run() {
* // compute primes...
* }
* }
* </pre>
* To start this thread you need to do the following:
* <pre>
* PrimeThread p = new PrimeThread();
* p.start();
* ...
* </pre>
* 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:
* <pre>
* class Primes implements Runnable {
* public void run() {
* // compute primes...
* }
* }
* </pre>
* To start this thread you need to do the following:
* <pre>
* Primes p = new Primes();
* new Thread(p).start();
* ...
* </pre>
* 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.
* <p>
* 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.
* <p><pre>
* import java.lang.*;
* <p>
* 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");
* }
* }<p>
* class threadtest01 {
* public static void main(String args[] ) {
* int failed = 0 ;
* <p>
* <b> Thread t1 = new Thread();</b>
* if(t1 != null) {
* System.out.println("new Thread() succeed");
* } else {
* System.out.println("new Thread() failed");
* failed++;
* } </pre>
* } <p>
*/
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();
}