1 packagejava.lang;2 importdalvik.system.VMStack;3 importjava.util.ArrayList;4 importjava.util.HashMap;5 importjava.util.List;6 importjava.util.Map;7 importlibcore.util.EmptyArray;8
9 /**
10 * A {@codeThread} is a concurrent unit of execution. It has its own call stack11 * for methods being invoked, their arguments and local variables. Each virtual12 * machine instance has at least one main {@codeThread} running when it is13 * started; typically, there are several others for housekeeping. The14 * application might decide to launch additional {@codeThread}s for specific15 * purposes.16 *
17 * {@codeThread}s in the same VM interact and synchronize by the use of shared18 * objects and monitors associated with these objects. Synchronized methods and19 * part of the API in {@linkObject} also allow {@codeThread}s to cooperate.20 *
21 * There are basically two main ways of having a {@codeThread} execute22 * application code. One is providing a new class that extends {@codeThread}23 * and overriding its {@link#run()} method. The other is providing a new24 * {@codeThread} instance with a {@linkRunnable} object during its creation.25 * In both cases, the {@link#start()} method must be called to actually execute26 * the new {@codeThread}.27 *
28 * Each {@codeThread} has an integer priority that basically determines the29 * amount of CPU time the {@codeThread} gets. It can be set using the30 * {@link#setPriority(int)} method. A {@codeThread} can also be made a daemon,31 * which makes it run in the background. The latter also affects VM termination32 * behavior: the VM does not terminate automatically as long as there are33 * non-daemon threads running.34 *35 *@seejava.lang.Object36 *@seejava.lang.ThreadGroup37 *38 */
39 public class Thread implementsRunnable {40 private static final int NANOS_PER_MILLI = 1000000;41
42 /**Park states*/
43 private static classParkState {44 /**park state indicating unparked*/
45 private static final int UNPARKED = 1;46 /**park state indicating preemptively unparked*/
47 private static final int PREEMPTIVELY_UNPARKED = 2;48 /**park state indicating parked*/
49 private static final int PARKED = 3;50 }51 /**
52 * A representation of a thread's state. A given thread may only be in one53 * state at a time.54 */
55 public enumState {56 /**
57 * The thread has been created, but has never been started.58 */
59 NEW,60 /**
61 * The thread may be run.62 */
63 RUNNABLE,64 /**
65 * The thread is blocked and waiting for a lock.66 */
67 BLOCKED,68 /**
69 * The thread is waiting.70 */
71 WAITING,72 /**
73 * The thread is waiting for a specified amount of time.74 */
75 TIMED_WAITING,76 /**
77 * The thread has been terminated.78 */
79 TERMINATED80 }81 /**
82 * The maximum priority value allowed for a thread.83 */
84 public static final int MAX_PRIORITY = 10;85 /**
86 * The minimum priority value allowed for a thread.87 */
88 public static final int MIN_PRIORITY = 1;89 /**
90 * The normal (default) priority value assigned to threads.91 */
92 public static final int NORM_PRIORITY = 5;93 /*some of these are accessed directly by the VM; do not rename them*/
94 volatileVMThread vmThread;95 volatileThreadGroup group;96 volatile booleandaemon;97 volatileString name;98 volatile intpriority;99 volatile longstackSize;100 Runnable target;101 private static int count = 0;102 /**
103 * Holds the thread's ID. We simply count upwards, so104 * each Thread has a unique ID.105 */
106 private longid;107 /**
108 * Normal thread local values.109 */
110 ThreadLocal.Values localValues;111 /**
112 * Inheritable thread local values.113 */
114 ThreadLocal.Values inheritableValues;115 /**Callbacks to run on interruption.*/
116 private final List interruptActions = new ArrayList();117 /**
118 * Holds the class loader for this Thread, in case there is one.119 */
120 privateClassLoader contextClassLoader;121 /**
122 * Holds the handler for uncaught exceptions in this Thread,123 * in case there is one.124 */
125 privateUncaughtExceptionHandler uncaughtHandler;126 /**
127 * Holds the default handler for uncaught exceptions, in case there is one.128 */
129 private staticUncaughtExceptionHandler defaultUncaughtHandler;130 /**
131 * Reflects whether this Thread has already been started. A Thread132 * can only be started once (no recycling). Also, we need it to deduce133 * the proper Thread status.134 */
135 boolean hasBeenStarted = false;136
137 /**the park state of the thread*/
138 private int parkState =ParkState.UNPARKED;139
140 /**The synchronization object responsible for this thread parking.*/
141 privateObject parkBlocker;142
143 /**
144 * Constructs a new {@codeThread} with no {@codeRunnable} object and a145 * newly generated name. The new {@codeThread} will belong to the same146 * {@codeThreadGroup} as the {@codeThread} calling this constructor.147 *148 *@seejava.lang.ThreadGroup149 *@seejava.lang.Runnable150 */
151 publicThread() {152 create(null, null, null, 0);153 }154 /**
155 * Constructs a new {@codeThread} with a {@codeRunnable} object and a156 * newly generated name. The new {@codeThread} will belong to the same157 * {@codeThreadGroup} as the {@codeThread} calling this constructor.158 *159 *@paramrunnable160 * a {@codeRunnable} whose method run
will be161 * executed by the new {@codeThread}162 *163 *@seejava.lang.ThreadGroup164 *@seejava.lang.Runnable165 */
166 publicThread(Runnable runnable) {167 create(null, runnable, null, 0);168 }169
170 /**
171 * Constructs a new {@codeThread} with a {@codeRunnable} object and name172 * provided. The new {@codeThread} will belong to the same {@code
173 * ThreadGroup} as the {@codeThread} calling this constructor.174 *175 *@paramrunnable176 * a {@codeRunnable} whose method run
will be177 * executed by the new {@codeThread}178 *@paramthreadName179 * the name for the {@codeThread} being created180 *181 *@seejava.lang.ThreadGroup182 *@seejava.lang.Runnable183 */
184 publicThread(Runnable runnable, String threadName) {185 if (threadName == null) {186 throw newNullPointerException();187 }188
189 create(null, runnable, threadName, 0);190 }191
192 /**
193 * Constructs a new {@codeThread} with no {@codeRunnable} object and the194 * name provided. The new {@codeThread} will belong to the same {@code
195 * ThreadGroup} as the {@codeThread} calling this constructor.196 *197 *@paramthreadName198 * the name for the {@codeThread} being created199 *200 *@seejava.lang.ThreadGroup201 *@seejava.lang.Runnable202 *203 */
204 publicThread(String threadName) {205 if (threadName == null) {206 throw newNullPointerException();207 }208
209 create(null, null, threadName, 0);210 }211
212 /**
213 * Constructs a new {@codeThread} with a {@codeRunnable} object and a214 * newly generated name. The new {@codeThread} will belong to the {@code
215 * ThreadGroup} passed as parameter.216 *217 *@paramgroup218 * {@codeThreadGroup} to which the new {@codeThread} will219 * belong220 *@paramrunnable221 * a {@codeRunnable} whose method run
will be222 * executed by the new {@codeThread}223 *@throwsIllegalThreadStateException224 * if group.destroy()
has already been done225 *@seejava.lang.ThreadGroup226 *@seejava.lang.Runnable227 */
228 publicThread(ThreadGroup group, Runnable runnable) {229 create(group, runnable, null, 0);230 }231
232 /**
233 * Constructs a new {@codeThread} with a {@codeRunnable} object, the given234 * name and belonging to the {@codeThreadGroup} passed as parameter.235 *236 *@paramgroup237 * ThreadGroup to which the new {@codeThread} will belong238 *@paramrunnable239 * a {@codeRunnable} whose method run
will be240 * executed by the new {@codeThread}241 *@paramthreadName242 * the name for the {@codeThread} being created243 *@throwsIllegalThreadStateException244 * if group.destroy()
has already been done245 *@seejava.lang.ThreadGroup246 *@seejava.lang.Runnable247 */
248 publicThread(ThreadGroup group, Runnable runnable, String threadName) {249 if (threadName == null) {250 throw newNullPointerException();251 }252
253 create(group, runnable, threadName, 0);254 }255
256 /**
257 * Constructs a new {@codeThread} with no {@codeRunnable} object, the258 * given name and belonging to the {@codeThreadGroup} passed as parameter.259 *260 *@paramgroup261 * {@codeThreadGroup} to which the new {@codeThread} will belong262 *@paramthreadName263 * the name for the {@codeThread} being created264 *@throwsIllegalThreadStateException265 * if group.destroy()
has already been done266 *@seejava.lang.ThreadGroup267 *@seejava.lang.Runnable268 */
269 publicThread(ThreadGroup group, String threadName) {270 if (threadName == null) {271 throw newNullPointerException();272 }273
274 create(group, null, threadName, 0);275 }276
277 /**
278 * Constructs a new {@codeThread} with a {@codeRunnable} object, the given279 * name and belonging to the {@codeThreadGroup} passed as parameter.280 *281 *@paramgroup282 * {@codeThreadGroup} to which the new {@codeThread} will283 * belong284 *@paramrunnable285 * a {@codeRunnable} whose method run
will be286 * executed by the new {@codeThread}287 *@paramthreadName288 * the name for the {@codeThread} being created289 *@paramstackSize290 * a stack size for the new {@codeThread}. This has a highly291 * platform-dependent interpretation. It may even be ignored292 * completely.293 *@throwsIllegalThreadStateException294 * if group.destroy()
has already been done295 *@seejava.lang.ThreadGroup296 *@seejava.lang.Runnable297 */
298 public Thread(ThreadGroup group, Runnable runnable, String threadName, longstackSize) {299 if (threadName == null) {300 throw newNullPointerException();301 }302 create(group, runnable, threadName, stackSize);303 }304
305 /**
306 * Package-scope method invoked by Dalvik VM to create "internal"307 * threads or attach threads created externally.308 *309 * Don't call Thread.currentThread(), since there may not be such310 * a thing (e.g. for Main).311 */
312 Thread(ThreadGroup group, String name, int priority, booleandaemon) {313 synchronized (Thread.class) {314 id = ++Thread.count;315 }316
317 if (name == null) {318 this.name = "Thread-" +id;319 } else{320 this.name =name;321 }322
323 if (group == null) {324 throw new InternalError("group not specified");325 }326
327 this.group =group;328
329 this.target = null;330 this.stackSize = 0;331 this.priority =priority;332 this.daemon =daemon;333
334 /*add ourselves to our ThreadGroup of choice*/
335 this.group.addThread(this);336 }337
338 /**
339 * Initializes a new, existing Thread object with a runnable object,340 * the given name and belonging to the ThreadGroup passed as parameter.341 * This is the method that the several public constructors delegate their342 * work to.343 *344 *@paramgroup ThreadGroup to which the new Thread will belong345 *@paramrunnable a java.lang.Runnable whose method run
will346 * be executed by the new Thread347 *@paramthreadName Name for the Thread being created348 *@paramstackSize Platform dependent stack size349 *@throwsIllegalThreadStateException if group.destroy()
has350 * already been done351 *@seejava.lang.ThreadGroup352 *@seejava.lang.Runnable353 */
354 private void create(ThreadGroup group, Runnable runnable, String threadName, longstackSize) {355 Thread currentThread =Thread.currentThread();356 if (group == null) {357 group =currentThread.getThreadGroup();358 }359
360 if(group.isDestroyed()) {361 throw new IllegalThreadStateException("Group already destroyed");362 }363
364 this.group =group;365
366 synchronized (Thread.class) {367 id = ++Thread.count;368 }369
370 if (threadName == null) {371 this.name = "Thread-" +id;372 } else{373 this.name =threadName;374 }375
376 this.target =runnable;377 this.stackSize =stackSize;378
379 this.priority =currentThread.getPriority();380
381 this.contextClassLoader =currentThread.contextClassLoader;382
383 //Transfer over InheritableThreadLocals.
384 if (currentThread.inheritableValues != null) {385 inheritableValues = newThreadLocal.Values(currentThread.inheritableValues);386 }387
388 //add ourselves to our ThreadGroup of choice
389 this.group.addThread(this);390 }391
392 /**
393 * Returns the number of active {@codeThread}s in the running {@code
394 * Thread}'s group and its subgroups.395 *396 *@returnthe number of {@codeThread}s397 */
398 public static intactiveCount() {399 returncurrentThread().getThreadGroup().activeCount();400 }401
402 /**
403 * Does nothing.404 */
405 public final voidcheckAccess() {406 }407
408 /**
409 * Returns the number of stack frames in this thread.410 *411 *@returnNumber of stack frames412 *@deprecatedThe results of this call were never well defined. To make413 * things worse, it would depend on whether the Thread was414 * suspended or not, and suspend was deprecated too.415 */
416 @Deprecated417 public intcountStackFrames() {418 returngetStackTrace().length;419 }420
421 /**
422 * Returns the Thread of the caller, that is, the current Thread.423 *424 *@returnthe current Thread.425 */
426 public staticThread currentThread() {427 returnVMThread.currentThread();428 }429
430 /**
431 * Destroys the receiver without any monitor cleanup.432 *433 *@deprecatedNot implemented.434 */
435 @Deprecated436 public voiddestroy() {437 throw new NoSuchMethodError("Thread.destroy()"); //TODO Externalize???
438 }439
440 /**
441 * Prints to the standard error stream a text representation of the current442 * stack for this Thread.443 *444 *@seeThrowable#printStackTrace()445 */
446 public static voiddumpStack() {447 new Throwable("stack dump").printStackTrace();448 }449
450 /**
451 * Copies an array with all Threads which are in the same ThreadGroup as the452 * receiver - and subgroups - into the array threads
passed as453 * parameter. If the array passed as parameter is too small no exception is454 * thrown - the extra elements are simply not copied.455 *456 *@paramthreads457 * array into which the Threads will be copied458 *@returnHow many Threads were copied over459 */
460 public static intenumerate(Thread[] threads) {461 Thread thread =Thread.currentThread();462 returnthread.getThreadGroup().enumerate(threads);463 }464
465 /**
466 * Returns a map of all the currently live threads to their stack traces.467 */
468 public static MapgetAllStackTraces() {469 Map map = new HashMap();470
471 //Find out how many live threads we have. Allocate a bit more472 //space than needed, in case new ones are just being created.
473 int count =ThreadGroup.mSystem.activeCount();474 Thread[] threads = new Thread[count + count / 2];475
476 //Enumerate the threads and collect the stacktraces.
477 count =ThreadGroup.mSystem.enumerate(threads);478 for (int i = 0; i < count; i++) {479 map.put(threads[i], threads[i].getStackTrace());480 }481
482 returnmap;483 }484
485 /**
486 * Returns the context ClassLoader for this Thread.487 *488 *@returnClassLoader The context ClassLoader489 *@seejava.lang.ClassLoader490 *@see#getContextClassLoader()491 */
492 publicClassLoader getContextClassLoader() {493 returncontextClassLoader;494 }495
496 /**
497 * Returns the default exception handler that's executed when uncaught498 * exception terminates a thread.499 *500 *@returnan {@linkUncaughtExceptionHandler} or null
if501 * none exists.502 */
503 public staticUncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {504 returndefaultUncaughtHandler;505 }506
507 /**
508 * Returns the thread's identifier. The ID is a positive long
509 * generated on thread creation, is unique to the thread, and doesn't change510 * during the lifetime of the thread; the ID may be reused after the thread511 * has been terminated.512 *513 *@returnthe thread's ID.514 */
515 public longgetId() {516 returnid;517 }518
519 /**
520 * Returns the name of the Thread.521 *522 *@returnthe Thread's name523 */
524 public finalString getName() {525 returnname;526 }527
528 /**
529 * Returns the priority of the Thread.530 *531 *@returnthe Thread's priority532 *@seeThread#setPriority533 */
534 public final intgetPriority() {535 returnpriority;536 }537
538 /**
539 * Returns an array of {@linkStackTraceElement} representing the current thread's stack.540 */
541 publicStackTraceElement[] getStackTrace() {542 StackTraceElement ste[] = VMStack.getThreadStackTrace(this);543 return ste != null ?ste : EmptyArray.STACK_TRACE_ELEMENT;544 }545
546 /**
547 * Returns the current state of the Thread. This method is useful for548 * monitoring purposes.549 *550 *@returna {@linkState} value.551 */
552 publicState getState() {553 //TODO This is ugly and should be implemented better.
554 VMThread vmt = this.vmThread;555
556 //Make sure we have a valid reference to an object. If native code557 //deletes the reference we won't run into a null reference later.
558 VMThread thread =vmThread;559 if (thread != null) {560 //If the Thread Object became invalid or was not yet started,561 //getStatus() will return -1.
562 int state =thread.getStatus();563 if(state != -1) {564 returnVMThread.STATE_MAP[state];565 }566 }567 return hasBeenStarted ?Thread.State.TERMINATED : Thread.State.NEW;568 }569
570 /**
571 * Returns the ThreadGroup to which this Thread belongs.572 *573 *@returnthe Thread's ThreadGroup574 */
575 public finalThreadGroup getThreadGroup() {576 //TODO This should actually be done at native termination.
577 if (getState() ==Thread.State.TERMINATED) {578 return null;579 } else{580 returngroup;581 }582 }583
584 /**
585 * Returns the thread's uncaught exception handler. If not explicitly set,586 * then the ThreadGroup's handler is returned. If the thread is terminated,587 * then null
is returned.588 *589 *@returnan {@linkUncaughtExceptionHandler} instance or {@codenull}.590 */
591 publicUncaughtExceptionHandler getUncaughtExceptionHandler() {592 if (uncaughtHandler != null)593 returnuncaughtHandler;594 else
595 return group; //ThreadGroup is instance of UEH
596 }597
598 /**
599 * Posts an interrupt request to this {@codeThread}. The behavior depends on600 * the state of this {@codeThread}:601 *
- 602 *
- 603 * {@codeThread}s blocked in one of {@codeObject}'s {@codewait()} methods604 * or one of {@codeThread}'s {@codejoin()} or {@codesleep()} methods will605 * be woken up, their interrupt status will be cleared, and they receive an606 * {@linkInterruptedException}.607 *
- 608 * {@codeThread}s blocked in an I/O operation of an609 * {@linkjava.nio.channels.InterruptibleChannel} will have their interrupt610 * status set and receive an611 * {@linkjava.nio.channels.ClosedByInterruptException}. Also, the channel612 * will be closed.613 *
- 614 * {@codeThread}s blocked in a {@linkjava.nio.channels.Selector} will have615 * their interrupt status set and return immediately. They don't receive an616 * exception in this case.617 *
- 618 *619 *@seeThread#interrupted620 *@seeThread#isInterrupted621 */
622 public voidinterrupt() {623 synchronized(interruptActions) {624 for (int i = interruptActions.size() - 1; i >= 0; i--) {625 interruptActions.get(i).run();626 }627 }628
629 VMThread vmt = this.vmThread;630 if (vmt != null) {631 vmt.interrupt();632 }633 }634
635 /**
636 * Returns a
boolean
indicating whether the current Thread (637 *currentThread()
) has a pending interrupt request (638 * true
) or not (false
). It also has the side-effect of639 * clearing the flag.640 *641 *@returnaboolean
indicating the interrupt status642 *@seeThread#currentThread643 *@seeThread#interrupt644 *@seeThread#isInterrupted645 */646 public static booleaninterrupted() {647 returnVMThread.interrupted();648 }649
650 /**
651 * Returns
true
if the receiver has already been started and652 * still runs code (hasn't died yet). Returnsfalse
either if653 * the receiver hasn't been started yet or if it has already started and run654 * to completion and died.655 *656 *@returnaboolean
indicating the liveness of the Thread657 *@seeThread#start658 */659 public final booleanisAlive() {660 return (vmThread != null);661 }662
663 /**
664 * Returns a
boolean
indicating whether the receiver is a665 * daemon Thread (true
) or not (false
) A666 * daemon Thread only runs as long as there are non-daemon Threads running.667 * When the last non-daemon Thread ends, the whole program ends no matter if668 * it had daemon Threads still running or not.669 *670 *@returnaboolean
indicating whether the Thread is a daemon671 *@seeThread#setDaemon672 */673 public final booleanisDaemon() {674 returndaemon;675 }676
677 /**
678 * Returns a
boolean
indicating whether the receiver has a679 * pending interrupt request (true
) or not (680 *false
)681 *682 *@returnaboolean
indicating the interrupt status683 *@seeThread#interrupt684 *@seeThread#interrupted685 */686 public booleanisInterrupted() {687 VMThread vmt = this.vmThread;688 if (vmt != null) {689 returnvmt.isInterrupted();690 }691
692 return false;693 }694
695 /**
696 * Blocks the current Thread (
Thread.currentThread()
) until697 * the receiver finishes its execution and dies.698 *699 *@throwsInterruptedException ifinterrupt()
was called for700 * the receiver while it was in thejoin()
call701 *@seeObject#notifyAll702 *@seejava.lang.ThreadDeath703 */704 public final void join() throwsInterruptedException {705 VMThread t =vmThread;706 if (t == null) {707 return;708 }709
710 synchronized(t) {711 while(isAlive()) {712 t.wait();713 }714 }715 }716
717 /**
718 * Blocks the current Thread (
Thread.currentThread()
) until719 * the receiver finishes its execution and dies or the specified timeout720 * expires, whatever happens first.721 *722 *@parammillis The maximum time to wait (in milliseconds).723 *@throwsInterruptedException ifinterrupt()
was called for724 * the receiver while it was in thejoin()
call725 *@seeObject#notifyAll726 *@seejava.lang.ThreadDeath727 */728 public final void join(long millis) throwsInterruptedException {729 join(millis, 0);730 }731
732 /**
733 * Blocks the current Thread (
Thread.currentThread()
) until734 * the receiver finishes its execution and dies or the specified timeout735 * expires, whatever happens first.736 *737 *@parammillis The maximum time to wait (in milliseconds).738 *@paramnanos Extra nanosecond precision739 *@throwsInterruptedException ifinterrupt()
was called for740 * the receiver while it was in thejoin()
call741 *@seeObject#notifyAll742 *@seejava.lang.ThreadDeath743 */744 public final void join(long millis, int nanos) throwsInterruptedException {745 if (millis < 0 || nanos < 0 || nanos >=NANOS_PER_MILLI) {746 throw newIllegalArgumentException();747 }748
749 //avoid overflow: if total > 292,277 years, just wait forever
750 boolean overflow = millis >= (Long.MAX_VALUE - nanos) /NANOS_PER_MILLI;751 boolean forever = (millis | nanos) == 0;752 if (forever |overflow) {753 join();754 return;755 }756
757 VMThread t =vmThread;758 if (t == null) {759 return;760 }761
762 synchronized(t) {763 if (!isAlive()) {764 return;765 }766
767 //guaranteed not to overflow
768 long nanosToWait = millis * NANOS_PER_MILLI +nanos;769
770 //wait until this thread completes or the timeout has elapsed
771 long start =System.nanoTime();772 while (true) {773 t.wait(millis, nanos);774 if (!isAlive()) {775 break;776 }777 long nanosElapsed = System.nanoTime() -start;778 long nanosRemaining = nanosToWait -nanosElapsed;779 if (nanosRemaining <= 0) {780 break;781 }782 millis = nanosRemaining /NANOS_PER_MILLI;783 nanos = (int) (nanosRemaining - millis *NANOS_PER_MILLI);784 }785 }786 }787
788 /**
789 * Throws {@codeUnsupportedOperationException}.790 *791 *@seeThread#suspend()792 *@deprecatedUsed with deprecated method {@linkThread#suspend}793 */
794 @Deprecated795 public final voidresume() {796 throw newUnsupportedOperationException();797 }798
799 /**
800 * Calls the
run()
method of the Runnable object the receiver801 * holds. If no Runnable is set, does nothing.802 *803 *@seeThread#start804 */805 public voidrun() {806 if (target != null) {807 target.run();808 }809 }810
811 /**
812 * Set the context ClassLoader for the receiver.813 *814 *@paramcl The context ClassLoader815 *@see#getContextClassLoader()816 */
817 public voidsetContextClassLoader(ClassLoader cl) {818 contextClassLoader =cl;819 }820
821 /**
822 * Set if the receiver is a daemon Thread or not. This can only be done823 * before the Thread starts running.824 *825 *@paramisDaemon826 * indicates whether the Thread should be daemon or not827 *@seeThread#isDaemon828 */
829 public final void setDaemon(booleanisDaemon) {830 if(hasBeenStarted) {831 throw new IllegalThreadStateException("Thread already started."); //TODO Externalize?
832 }833
834 if (vmThread == null) {835 daemon =isDaemon;836 }837 }838
839 /**
840 * Sets the default uncaught exception handler. This handler is invoked in841 * case any Thread dies due to an unhandled exception.842 *843 *@paramhandler844 * The handler to set or null.845 */
846 public static voidsetDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {847 Thread.defaultUncaughtHandler =handler;848 }849
850 /**
851 * Adds a runnable to be invoked upon interruption. If this thread has852 * already been interrupted, the runnable will be invoked immediately. The853 * action should be idempotent as it may be invoked multiple times for a854 * single interruption.855 *856 *
Each call to this method must be matched with a corresponding call to857 * {@link#popInterruptAction$}.858 *859 * @hide used by NIO860 */
861 public final voidpushInterruptAction$(Runnable interruptAction) {862 synchronized(interruptActions) {863 interruptActions.add(interruptAction);864 }865
866 if (interruptAction != null &&isInterrupted()) {867 interruptAction.run();868 }869 }870
871 /**
872 * Removes {@codeinterruptAction} so it is not invoked upon interruption.873 *874 *@paraminterruptAction the pushed action, used to check that the call875 * stack is correctly nested.876 *877 * @hide used by NIO878 */
879 public final voidpopInterruptAction$(Runnable interruptAction) {880 synchronized(interruptActions) {881 Runnable removed = interruptActions.remove(interruptActions.size() - 1);882 if (interruptAction !=removed) {883 throw newIllegalArgumentException(884 "Expected " + interruptAction + " but was " +removed);885 }886 }887 }888
889 /**
890 * Sets the name of the Thread.891 *892 *@paramthreadName the new name for the Thread893 *@seeThread#getName894 */
895 public final voidsetName(String threadName) {896 if (threadName == null) {897 throw newNullPointerException();898 }899
900 name =threadName;901 VMThread vmt = this.vmThread;902 if (vmt != null) {903 /*notify the VM that the thread name has changed*/
904 vmt.nameChanged(threadName);905 }906 }907
908 /**
909 * Sets the priority of the Thread. Note that the final priority set may not910 * be the parameter that was passed - it will depend on the receiver's911 * ThreadGroup. The priority cannot be set to be higher than the receiver's912 * ThreadGroup's maxPriority().913 *914 *@parampriority915 * new priority for the Thread916 *@throwsIllegalArgumentException917 * if the new priority is greater than Thread.MAX_PRIORITY or918 * less than Thread.MIN_PRIORITY919 *@seeThread#getPriority920 */
921 public final void setPriority(intpriority) {922 if (priority < Thread.MIN_PRIORITY || priority >Thread.MAX_PRIORITY) {923 throw new IllegalArgumentException("Priority out of range"); //TODO Externalize?
924 }925
926 if (priority >group.getMaxPriority()) {927 priority =group.getMaxPriority();928 }929
930 this.priority =priority;931
932 VMThread vmt = this.vmThread;933 if (vmt != null) {934 vmt.setPriority(priority);935 }936 }937
938 /**
939 *
940 * Sets the uncaught exception handler. This handler is invoked in case this941 * Thread dies due to an unhandled exception.942 *
943 *944 *@paramhandler945 * The handler to set ornull
.946 */947 public voidsetUncaughtExceptionHandler(UncaughtExceptionHandler handler) {948 uncaughtHandler =handler;949 }950
951 /**
952 * Causes the thread which sent this message to sleep for the given interval953 * of time (given in milliseconds). The precision is not guaranteed - the954 * Thread may sleep more or less than requested.955 *956 *@paramtime957 * The time to sleep in milliseconds.958 *@throwsInterruptedException959 * if
interrupt()
was called for this Thread while960 * it was sleeping961 *@seeThread#interrupt()962 */963 public static void sleep(long time) throwsInterruptedException {964 Thread.sleep(time, 0);965 }966
967 /**
968 * Causes the thread which sent this message to sleep for the given interval969 * of time (given in milliseconds and nanoseconds). The precision is not970 * guaranteed - the Thread may sleep more or less than requested.971 *972 *@parammillis973 * The time to sleep in milliseconds.974 *@paramnanos975 * Extra nanosecond precision976 *@throwsInterruptedException977 * if
interrupt()
was called for this Thread while978 * it was sleeping979 *@seeThread#interrupt()980 */981 public static void sleep(long millis, int nanos) throwsInterruptedException {982 VMThread.sleep(millis, nanos);983 }984
985 /**
986 * Starts the new Thread of execution. The
run()
method of987 * the receiver will be called by the receiver Thread itself (and not the988 * Thread callingstart()
).989 *990 *@throwsIllegalThreadStateException if the Thread has been started before991 *992 *@seeThread#run993 */994 public synchronized voidstart() {995 if(hasBeenStarted) {996 throw new IllegalThreadStateException("Thread already started."); //TODO Externalize?
997 }998
999 hasBeenStarted = true;1000
1001 VMThread.create(this, stackSize);1002 }1003
1004 /**
1005 * Requests the receiver Thread to stop and throw ThreadDeath. The Thread is1006 * resumed if it was suspended and awakened if it was sleeping, so that it1007 * can proceed to throw ThreadDeath.1008 *1009 *@deprecatedbecause stopping a thread in this manner is unsafe and can1010 * leave your application and the VM in an unpredictable state.1011 */
1012 @Deprecated1013 public final voidstop() {1014 stop(newThreadDeath());1015 }1016
1017 /**
1018 * Throws {@codeUnsupportedOperationException}.1019 *1020 *@throwsNullPointerException if
throwable()
is1021 *null
1022 *@deprecatedbecause stopping a thread in this manner is unsafe and can1023 * leave your application and the VM in an unpredictable state.1024 */1025 @Deprecated1026 public final synchronized voidstop(Throwable throwable) {1027 throw newUnsupportedOperationException();1028 }1029
1030 /**
1031 * Throws {@codeUnsupportedOperationException}.1032 *1033 *@seeThread#resume()1034 *@deprecatedMay cause deadlocks.1035 */
1036 @Deprecated1037 public final voidsuspend() {1038 throw newUnsupportedOperationException();1039 }1040
1041 /**
1042 * Returns a string containing a concise, human-readable description of the1043 * Thread. It includes the Thread's name, priority, and group name.1044 *1045 *@returna printable representation for the receiver.1046 */
1047 @Override1048 publicString toString() {1049 return "Thread[" + name + "," + priority + "," + group.getName() + "]";1050 }1051
1052 /**
1053 * Causes the calling Thread to yield execution time to another Thread that1054 * is ready to run. The actual scheduling is implementation-dependent.1055 */
1056 public static voidyield() {1057 VMThread.yield();1058 }1059
1060 /**
1061 * Indicates whether the current Thread has a monitor lock on the specified1062 * object.1063 *1064 *@paramobject the object to test for the monitor lock1065 *@returntrue if the current thread has a monitor lock on the specified1066 * object; false otherwise1067 */
1068 public static booleanholdsLock(Object object) {1069 returncurrentThread().vmThread.holdsLock(object);1070 }1071
1072 /**
1073 * Implemented by objects that want to handle cases where a thread is being1074 * terminated by an uncaught exception. Upon such termination, the handler1075 * is notified of the terminating thread and causal exception. If there is1076 * no explicit handler set then the thread's group is the default handler.1077 */
1078 public static interfaceUncaughtExceptionHandler {1079 /**
1080 * The thread is being terminated by an uncaught exception. Further1081 * exceptions thrown in this method are prevent the remainder of the1082 * method from executing, but are otherwise ignored.1083 *1084 *@paramthread the thread that has an uncaught exception1085 *@paramex the exception that was thrown1086 */
1087 voiduncaughtException(Thread thread, Throwable ex);1088 }1089
1090 /**
1091 * Unparks this thread. This unblocks the thread it if it was1092 * previously parked, or indicates that the thread is "preemptively1093 * unparked" if it wasn't already parked. The latter means that the1094 * next time the thread is told to park, it will merely clear its1095 * latent park bit and carry on without blocking.1096 *1097 *
See {@linkjava.util.concurrent.locks.LockSupport} for more1098 * in-depth information of the behavior of this method.
1099 *1100 * @hide for Unsafe1101 */1102 public voidunpark() {1103 VMThread vmt =vmThread;1104
1105 if (vmt == null) {1106 /*
1107 * vmThread is null before the thread is start()ed. In1108 * this case, we just go ahead and set the state to1109 * PREEMPTIVELY_UNPARKED. Since this happens before the1110 * thread is started, we don't have to worry about1111 * synchronizing with it.1112 */
1113 parkState =ParkState.PREEMPTIVELY_UNPARKED;1114 return;1115 }1116
1117 synchronized(vmt) {1118 switch(parkState) {1119 caseParkState.PREEMPTIVELY_UNPARKED: {1120 /*
1121 * Nothing to do in this case: By definition, a1122 * preemptively unparked thread is to remain in1123 * the preemptively unparked state if it is told1124 * to unpark.1125 */
1126 break;1127 }1128 caseParkState.UNPARKED: {1129 parkState =ParkState.PREEMPTIVELY_UNPARKED;1130 break;1131 }1132 default /*parked*/: {1133 parkState =ParkState.UNPARKED;1134 vmt.notifyAll();1135 break;1136 }1137 }1138 }1139 }1140
1141 /**
1142 * Parks the current thread for a particular number of nanoseconds, or1143 * indefinitely. If not indefinitely, this method unparks the thread1144 * after the given number of nanoseconds if no other thread unparks it1145 * first. If the thread has been "preemptively unparked," this method1146 * cancels that unparking and returns immediately. This method may1147 * also return spuriously (that is, without the thread being told to1148 * unpark and without the indicated amount of time elapsing).1149 *1150 *
See {@linkjava.util.concurrent.locks.LockSupport} for more1151 * in-depth information of the behavior of this method.
1152 *1153 *This method must only be called when
this
is the current1154 * thread.1155 *1156 *@paramnanos number of nanoseconds to park for or0
1157 * to park indefinitely1158 *@throwsIllegalArgumentException thrown ifnanos < 0
1159 *1160 * @hide for Unsafe1161 */1162 public void parkFor(longnanos) {1163 VMThread vmt =vmThread;1164
1165 if (vmt == null) {1166 //Running threads should always have an associated vmThread.
1167 throw newAssertionError();1168 }1169
1170 synchronized(vmt) {1171 switch(parkState) {1172 caseParkState.PREEMPTIVELY_UNPARKED: {1173 parkState =ParkState.UNPARKED;1174 break;1175 }1176 caseParkState.UNPARKED: {1177 long millis = nanos /NANOS_PER_MILLI;1178 nanos %=NANOS_PER_MILLI;1179
1180 parkState =ParkState.PARKED;1181 try{1182 vmt.wait(millis, (int) nanos);1183 } catch(InterruptedException ex) {1184 interrupt();1185 } finally{1186 /*
1187 * Note: If parkState manages to become1188 * PREEMPTIVELY_UNPARKED before hitting this1189 * code, it should left in that state.1190 */
1191 if (parkState ==ParkState.PARKED) {1192 parkState =ParkState.UNPARKED;1193 }1194 }1195 break;1196 }1197 default /*parked*/: {1198 throw newAssertionError(1199 "shouldn't happen: attempt to repark");1200 }1201 }1202 }1203 }1204
1205 /**
1206 * Parks the current thread until the specified system time. This1207 * method attempts to unpark the current thread immediately after1208 *
System.currentTimeMillis()
reaches the specified1209 * value, if no other thread unparks it first. If the thread has1210 * been "preemptively unparked," this method cancels that1211 * unparking and returns immediately. This method may also return1212 * spuriously (that is, without the thread being told to unpark1213 * and without the indicated amount of time elapsing).1214 *1215 *See {@linkjava.util.concurrent.locks.LockSupport} for more1216 * in-depth information of the behavior of this method.
1217 *1218 *This method must only be called when
this
is the1219 * current thread.1220 *1221 *@paramtime the time after which the thread should be unparked,1222 * in absolute milliseconds-since-the-epoch1223 *1224 * @hide for Unsafe1225 */1226 public void parkUntil(longtime) {1227 VMThread vmt =vmThread;1228
1229 if (vmt == null) {1230 //Running threads should always have an associated vmThread.
1231 throw newAssertionError();1232 }1233
1234 synchronized(vmt) {1235 /*
1236 * Note: This conflates the two time bases of "wall clock"1237 * time and "monotonic uptime" time. However, given that1238 * the underlying system can only wait on monotonic time,1239 * it is unclear if there is any way to avoid the1240 * conflation. The downside here is that if, having1241 * calculated the delay, the wall clock gets moved ahead,1242 * this method may not return until well after the wall1243 * clock has reached the originally designated time. The1244 * reverse problem (the wall clock being turned back)1245 * isn't a big deal, since this method is allowed to1246 * spuriously return for any reason, and this situation1247 * can safely be construed as just such a spurious return.1248 */
1249 long delayMillis = time -System.currentTimeMillis();1250
1251 if (delayMillis <= 0) {1252 parkState =ParkState.UNPARKED;1253 } else{1254 parkFor(delayMillis *NANOS_PER_MILLI);1255 }1256 }1257 }1258 }