com.google.gwt.emul.java.lang.Thread Maven / Gradle / Ivy
package java.lang;
/**
* A thread is a thread of execution in a program. The Java
* Virtual Machine allows an application to have multiple threads of
* execution running concurrently.
*
* Compiled GWT does not have support for concurrency or blocking.
* Although sleep can be achieved with a java applet,
* it still causes many browsers to block, which will only waste cpu, cause huge glitches
* and lead to generally terrible user experience.
*
* So, for now, a Thread is simply a Timer-backed compatibility class.
*
* Work is being done, however, to implement a special generator to enable multi-threading.
*
* Using the reflection support, we can take translate a Class<? extends Thread>
* into a runAsync block of code which exports all reflection data needed to implement run()
* as javascript commands into a web worker, which can be sent the script, a blob of
* constants, and then accept "foreign object messages", to be able to operate on Objects
* from the root page, and return Objects that make sense in the root page context.
*
* It will actually be a subclass of Thread, called GwtThread, which will launch
* a dedicated compile for that thread (it's own "classloader"), and the proxy
* instance owned by the root page will handle de/serialization between threads.
*
* This communication will likely be done with typed in() and out() methods,
* such that it will be trivial to stream objects through a thread (especially nice
* once lambdas are supported in GWT).
*
* In future iterations, a generic ReflectionThread could be implemented to work in
* multi-classloader threaded environments; by transpiling the run method into reflection statements,
* it will be possible to write code as if it is all running in the same environment,
* but behind the scenes, just reduce everything to constants and reflection api calls.
*
*/
public class Thread implements Runnable {
interface Provider {
T get();
}
static {
//prepare our virtual thread manager
}
private char name[];
private int priority = NORM_PRIORITY;
private Runnable target;
/**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
/* If stop was called before start */
private boolean stopBeforeStart;
private static Provider currentThread = new Provider(){
private transient Thread t;
public Thread get() {
return t == null ? (new Thread(null, "root") {
protected void init(Runnable target, String name, long stackSize) {
t = this;// first one is root!
// note that init is called synchronously from all Thread constructors.
this.cl = ClassLoader.getSystemClassLoader();
super.init(target, name, stackSize);
};
}) : t;
};
};
// /* Remembered Throwable from stop before start */
// private Throwable throwableFromStop;
/* Whether or not the Thread has been completely constructed;
* init or clone method has successfully completed */
private Thread me; // null
private State state;
protected ClassLoader cl;
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static Thread currentThread(){
return currentThread.get();
}
/**
* Causes the currently executing thread object to temporarily pause
* and allow other threads to execute.
*/
public static void yield(){
// does nothing in gwt.
// might be used to ping workers to tell them to pause processing
}
/**
* Causes the currently executing thread to sleep (temporarily cease
* execution) for the specified number of milliseconds, subject to
* the precision and accuracy of system timers and schedulers. The thread
* does not lose ownership of any monitors.
*
* @param millis the length of time to sleep in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The interrupted status of the
* current thread is cleared when this exception is thrown.
* @see Object#notify()
*/
public static void sleep(long millis) throws InterruptedException{
sleep(millis, 0);
}
public static void sleep(long millis, int nanos) throws InterruptedException{
}
/**
* Initializes a Thread.
* @param target the object whose run() method gets called
* @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.
*/
protected void init(Runnable target, String name,
long stackSize) {
Thread parent = currentThread();
this.cl = parent.cl;
this.priority = parent.getPriority();
this.name = name.toCharArray();
this.target = target;
setPriority(priority);
this.me = this;
}
/**
* 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.
*
* @see #Thread(ThreadGroup, Runnable, String)
*/
public Thread() {
init(null, "Thread-" + hashCode(), 0);
}
/**
* 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 #Thread(ThreadGroup, Runnable, String)
*/
public Thread(Runnable target) {
init(target, "Thread-" + hashCode(), 0);
}
/**
* Allocates a new Thread
object.
*
* @param target the object whose run
method is called.
* @param name the name of the new thread.
*/
public Thread(Runnable target, String name) {
init(target, name, 0);
}
/**
* Causes this thread to begin execution;
* This is achieved in gwt using javascript timeouts;
* the scheduler tries to virtualize some functionality of threads,
* but cannot achieve proper blocking, so beware discrepancies with normal java threading.
*
* In particular, {@link #sleep(long)} and {@link #yield()} will both throw unchecked exceptions,
* which our scheduling virtualizer will catch to determine how long to wait until servicing a thread again.
*
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
public synchronized void start() {
if (!stopBeforeStart) {
//add current thread to scheduler
setTimeout(new Runnable() {
@Override
public void run() {
if (stopBeforeStart)return;
Provider parent = currentThread;
try {
currentThread = new Provider() {
public Thread get() {
return Thread.this;
}
};
Thread.this.run();
} finally {
currentThread = parent;
}
}
});
}
}
private static native void setTimeout(Runnable r)
/*-{
$wnd.setTimeout($entry(function(){[email protected]::run()();}), 1);
}-*/;
/**
* If this thread was constructed using a separate
* Runnable
run object, then that
* Runnable
object's run
method is called;
* otherwise, this method does nothing and returns.
*
* Subclasses of Thread
should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
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() {
/* Aggressively null out all reference fields */
target = null;
/* Speed the release of some of these resources */
uncaughtExceptionHandler = null;
//TODO: remove this thread from all active maps
}
/**
* Forces the thread to stop executing.
*
* In gwt, this merely prevents the thread from ever starting.
*/
@Deprecated
public final void stop() {
stopBeforeStart = true;
exit();
}
@Deprecated
public final synchronized void stop(Throwable obj) {
stopBeforeStart = true;
exit();
}
/**
* Interrupts this thread.
*
* Does nothing in gwt.
*/
public void interrupt() {
}
/**
* Tests whether the current thread has been interrupted. The
* interrupted status of the thread is cleared by this method. In
* other words, if this method were to be called twice in succession, the
* second call would return false (unless the current thread were
* interrupted again, after the first call had cleared its interrupted
* status and before the second call had examined it).
*
*
A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return true
if the current thread has been interrupted;
* false
otherwise.
* @see #isInterrupted()
* @revised 6.0
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* Tests whether this thread has been interrupted. The interrupted
* status of the thread is unaffected by this method.
*
*
A thread interruption ignored because a thread was not alive
* at the time of the interrupt will be reflected by this method
* returning false.
*
* @return true
if this thread has been interrupted;
* false
otherwise.
* @see #interrupted()
* @revised 6.0
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* Tests if some Thread has been interrupted. The interrupted state
* is reset or not based on the value of ClearInterrupted that is
* passed.
*/
private boolean isInterrupted(boolean ClearInterrupted){
return false;//TODO: store a flag
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return true
if this thread is alive;
* false
otherwise.
*/
public final boolean isAlive(){
return true;//TODO: store a flag
}
@Deprecated
public final void suspend() {
//remove this thread from the running list
}
@Deprecated
public final void resume() {
//add this thread back to the running list
}
/**
* Changes the priority of this thread.
*/
public final void setPriority(int newPriority) {
if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
throw new IllegalArgumentException();
}
priority = newPriority;
}
/**
* Returns this thread's priority.
*
* @return this thread's priority.
* @see #setPriority
*/
public final int getPriority() {
return priority;
}
/**
* Changes the name of this thread to be equal to the argument
* name
.
*
* First the checkAccess
method of this thread is called
* with no arguments. This may result in throwing a
* SecurityException
.
*
* @param name the new name for this thread.
* @exception SecurityException if the current thread cannot modify this
* thread.
* @see #getName
* @see #checkAccess()
*/
public final void setName(String name) {
this.name = name.toCharArray();
}
/**
* Returns this thread's name.
*
* @return this thread's name.
* @see #setName(String)
*/
public final String getName() {
return String.valueOf(name);
}
/**
* Waits at most millis
milliseconds for this thread to
* die. A timeout of 0
means to wait forever.
*
* @param millis the time to wait in milliseconds.
* @exception InterruptedException if any thread has interrupted
* the current thread. The interrupted status of the
* current thread is cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
//TODO: virtualize join by having the task manager ignore Threads waiting on others.
Thread t = currentThread();
//make t wait on this
if (t == this)
return;
}
/**
* Waits for this thread to die.
*
* @exception InterruptedException if any thread has interrupted
* the current thread. The interrupted status of the
* current thread is cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
/**
* Prints a stack trace of the current thread to the standard error stream.
* This method is used only for debugging.
*
* @see Throwable#printStackTrace()
*/
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
/**
* 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[" + getName() + "," + getPriority() + "," +
"" + "]";
}
/**
* Returns the identifier of this Thread.
*
* In gwt, we simply use the thread's hashcode
*
* @return this thread's ID.
* @since 1.5
*/
public long getId() {
return hashCode();//we can safely use hashcode in gwt
}
/**
* A thread state. A thread can be in one of the following states:
*
* - {@link #NEW}
* A thread that has not yet started is in this state.
*
* - {@link #RUNNABLE}
* A thread executing in the Java virtual machine is in this state.
*
* - {@link #BLOCKED}
* A thread that is blocked waiting for a monitor lock
* is in this state.
*
* - {@link #WAITING}
* A thread that is waiting indefinitely for another thread to
* perform a particular action is in this state.
*
* - {@link #TIMED_WAITING}
* A thread that is waiting for another thread to perform an action
* for up to a specified waiting time is in this state.
*
* - {@link #TERMINATED}
* A thread that has exited is in this state.
*
*
*
*
* A thread can be in only one state at a given point in time.
* These states are virtual machine states which do not reflect
* any operating system thread states.
*
* @since 1.5
* @see #getState
*/
public enum State {
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
*
* - {@link Object#wait() Object.wait} with no timeout
* - {@link #join() Thread.join} with no timeout
*
*
* A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called Object.wait()
* on an object is waiting for another thread to call
* Object.notify() or Object.notifyAll() on
* that object. A thread that has called Thread.join()
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
*
* - {@link #sleep Thread.sleep}
* - {@link Object#wait(long) Object.wait} with timeout
* - {@link #join(long) Thread.join} with timeout
*
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
return state;
}
/**
* Interface for handlers invoked when a Thread abruptly
* terminates due to an uncaught exception.
* When a thread is about to terminate due to an uncaught exception
* the Java Virtual Machine will query the thread for its
* UncaughtExceptionHandler using
* {@link #getUncaughtExceptionHandler} and will invoke the handler's
* uncaughtException method, passing the thread and the
* exception as arguments.
* If a thread has not had its UncaughtExceptionHandler
* explicitly set, then its ThreadGroup object acts as its
* UncaughtExceptionHandler. If the ThreadGroup object
* has no
* special requirements for dealing with the exception, it can forward
* the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
* default uncaught exception handler}.
*
* @see #setDefaultUncaughtExceptionHandler
* @see #setUncaughtExceptionHandler
* @see ThreadGroup#uncaughtException
* @since 1.5
*/
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
*
Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
/**
* Set the default handler invoked when a thread abruptly terminates
* due to an uncaught exception, and no other handler has been defined
* for that thread.
*/
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
defaultUncaughtExceptionHandler = eh;
}
/**
* Returns the default handler invoked when a thread abruptly terminates
* due to an uncaught exception. If the returned value is null,
* there is no default.
* @since 1.5
* @see #setDefaultUncaughtExceptionHandler
*/
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
return defaultUncaughtExceptionHandler;
}
/**
* Returns the handler invoked when this thread abruptly terminates
* due to an uncaught exception. If this thread has not had an
* uncaught exception handler explicitly set then this thread's
* ThreadGroup object is returned, unless this thread
* has terminated, in which case null is returned.
*/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : getDefaultUncaughtExceptionHandler();
}
/**
* Set the handler invoked when this thread abruptly terminates
* due to an uncaught exception.
*/
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
uncaughtExceptionHandler = eh;
}
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
public ClassLoader getContextClassLoader(){
return cl;
}
public void setContextClassLoader(ClassLoader cl){
this.cl = cl;
}
}