Programming for thread in Java

Programming for thread in Java

Override Annotationhtml

 1 package java.lang;
 2 import java.lang.annotation.ElementType;
 3 import java.lang.annotation.Retention;
 4 import java.lang.annotation.RetentionPolicy;
 5 import java.lang.annotation.Target;
 6 
 7 /**
 8  * Annotation type used to mark methods that override a method declaration in a
 9  * superclass. Compilers produce an error if a method annotated with @Override
10  * does not actually override a method in a superclass.
11  *
12  * @since 1.5
13  */
14 @Target(ElementType.METHOD)
15 @Retention(RetentionPolicy.SOURCE)
16 public @interface Override {
17 }

Runnable Interfacejava

1 package java.lang;
2 /**
3  * Represents a command that can be executed. Often used to run code in a
4  * different {@link Thread}.
5  */
6 public interface Runnable {
7     public void run();
8 }

Thread Classredis

   1 package java.lang;
   2 import dalvik.system.VMStack;
   3 import java.util.ArrayList;
   4 import java.util.HashMap;
   5 import java.util.List;
   6 import java.util.Map;
   7 import libcore.util.EmptyArray;
   8 
   9 /**
  10  * A {@code Thread} is a concurrent unit of execution. It has its own call stack
  11  * for methods being invoked, their arguments and local variables. Each virtual
  12  * machine instance has at least one main {@code Thread} running when it is
  13  * started; typically, there are several others for housekeeping. The
  14  * application might decide to launch additional {@code Thread}s for specific
  15  * purposes.
  16  * <p>
  17  * {@code Thread}s in the same VM interact and synchronize by the use of shared
  18  * objects and monitors associated with these objects. Synchronized methods and
  19  * part of the API in {@link Object} also allow {@code Thread}s to cooperate.
  20  * <p>
  21  * There are basically two main ways of having a {@code Thread} execute
  22  * application code. One is providing a new class that extends {@code Thread}
  23  * and overriding its {@link #run()} method. The other is providing a new
  24  * {@code Thread} instance with a {@link Runnable} object during its creation.
  25  * In both cases, the {@link #start()} method must be called to actually execute
  26  * the new {@code Thread}.
  27  * <p>
  28  * Each {@code Thread} has an integer priority that basically determines the
  29  * amount of CPU time the {@code Thread} gets. It can be set using the
  30  * {@link #setPriority(int)} method. A {@code Thread} can also be made a daemon,
  31  * which makes it run in the background. The latter also affects VM termination
  32  * behavior: the VM does not terminate automatically as long as there are
  33  * non-daemon threads running.
  34  *
  35  * @see java.lang.Object
  36  * @see java.lang.ThreadGroup
  37  *
  38  */
  39 public class Thread implements Runnable {
  40     private static final int NANOS_PER_MILLI = 1000000;
  41 
  42     /** Park states */
  43     private static class ParkState {
  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 one
  53      * state at a time.
  54      */
  55     public enum State {
  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         TERMINATED
  80     }
  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     volatile VMThread vmThread;
  95     volatile ThreadGroup group;
  96     volatile boolean daemon;
  97     volatile String name;
  98     volatile int priority;
  99     volatile long stackSize;
 100     Runnable target;
 101     private static int count = 0;
 102     /**
 103      * Holds the thread's ID. We simply count upwards, so
 104      * each Thread has a unique ID.
 105      */
 106     private long id;
 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<Runnable> interruptActions = new ArrayList<Runnable>();
 117     /**
 118      * Holds the class loader for this Thread, in case there is one.
 119      */
 120     private ClassLoader contextClassLoader;
 121     /**
 122      * Holds the handler for uncaught exceptions in this Thread,
 123      * in case there is one.
 124      */
 125     private UncaughtExceptionHandler uncaughtHandler;
 126     /**
 127      * Holds the default handler for uncaught exceptions, in case there is one.
 128      */
 129     private static UncaughtExceptionHandler defaultUncaughtHandler;
 130     /**
 131      * Reflects whether this Thread has already been started. A Thread
 132      * can only be started once (no recycling). Also, we need it to deduce
 133      * 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     private Object parkBlocker;
 142 
 143     /**
 144      * Constructs a new {@code Thread} with no {@code Runnable} object and a
 145      * newly generated name. The new {@code Thread} will belong to the same
 146      * {@code ThreadGroup} as the {@code Thread} calling this constructor.
 147      *
 148      * @see java.lang.ThreadGroup
 149      * @see java.lang.Runnable
 150      */
 151     public Thread() {
 152         create(null, null, null, 0);
 153     }
 154     /**
 155      * Constructs a new {@code Thread} with a {@code Runnable} object and a
 156      * newly generated name. The new {@code Thread} will belong to the same
 157      * {@code ThreadGroup} as the {@code Thread} calling this constructor.
 158      *
 159      * @param runnable
 160      *            a {@code Runnable} whose method <code>run</code> will be
 161      *            executed by the new {@code Thread}
 162      *
 163      * @see java.lang.ThreadGroup
 164      * @see java.lang.Runnable
 165      */
 166     public Thread(Runnable runnable) {
 167         create(null, runnable, null, 0);
 168     }
 169 
 170     /**
 171      * Constructs a new {@code Thread} with a {@code Runnable} object and name
 172      * provided. The new {@code Thread} will belong to the same {@code
 173      * ThreadGroup} as the {@code Thread} calling this constructor.
 174      *
 175      * @param runnable
 176      *            a {@code Runnable} whose method <code>run</code> will be
 177      *            executed by the new {@code Thread}
 178      * @param threadName
 179      *            the name for the {@code Thread} being created
 180      *
 181      * @see java.lang.ThreadGroup
 182      * @see java.lang.Runnable
 183      */
 184     public Thread(Runnable runnable, String threadName) {
 185         if (threadName == null) {
 186             throw new NullPointerException();
 187         }
 188 
 189         create(null, runnable, threadName, 0);
 190     }
 191 
 192     /**
 193      * Constructs a new {@code Thread} with no {@code Runnable} object and the
 194      * name provided. The new {@code Thread} will belong to the same {@code
 195      * ThreadGroup} as the {@code Thread} calling this constructor.
 196      *
 197      * @param threadName
 198      *            the name for the {@code Thread} being created
 199      *
 200      * @see java.lang.ThreadGroup
 201      * @see java.lang.Runnable
 202      *
 203      */
 204     public Thread(String threadName) {
 205         if (threadName == null) {
 206             throw new NullPointerException();
 207         }
 208 
 209         create(null, null, threadName, 0);
 210     }
 211 
 212     /**
 213      * Constructs a new {@code Thread} with a {@code Runnable} object and a
 214      * newly generated name. The new {@code Thread} will belong to the {@code
 215      * ThreadGroup} passed as parameter.
 216      *
 217      * @param group
 218      *            {@code ThreadGroup} to which the new {@code Thread} will
 219      *            belong
 220      * @param runnable
 221      *            a {@code Runnable} whose method <code>run</code> will be
 222      *            executed by the new {@code Thread}
 223      * @throws IllegalThreadStateException
 224      *             if <code>group.destroy()</code> has already been done
 225      * @see java.lang.ThreadGroup
 226      * @see java.lang.Runnable
 227      */
 228     public Thread(ThreadGroup group, Runnable runnable) {
 229         create(group, runnable, null, 0);
 230     }
 231 
 232     /**
 233      * Constructs a new {@code Thread} with a {@code Runnable} object, the given
 234      * name and belonging to the {@code ThreadGroup} passed as parameter.
 235      *
 236      * @param group
 237      *            ThreadGroup to which the new {@code Thread} will belong
 238      * @param runnable
 239      *            a {@code Runnable} whose method <code>run</code> will be
 240      *            executed by the new {@code Thread}
 241      * @param threadName
 242      *            the name for the {@code Thread} being created
 243      * @throws IllegalThreadStateException
 244      *             if <code>group.destroy()</code> has already been done
 245      * @see java.lang.ThreadGroup
 246      * @see java.lang.Runnable
 247      */
 248     public Thread(ThreadGroup group, Runnable runnable, String threadName) {
 249         if (threadName == null) {
 250             throw new NullPointerException();
 251         }
 252 
 253         create(group, runnable, threadName, 0);
 254     }
 255 
 256     /**
 257      * Constructs a new {@code Thread} with no {@code Runnable} object, the
 258      * given name and belonging to the {@code ThreadGroup} passed as parameter.
 259      *
 260      * @param group
 261      *            {@code ThreadGroup} to which the new {@code Thread} will belong
 262      * @param threadName
 263      *            the name for the {@code Thread} being created
 264      * @throws IllegalThreadStateException
 265      *             if <code>group.destroy()</code> has already been done
 266      * @see java.lang.ThreadGroup
 267      * @see java.lang.Runnable
 268      */
 269     public Thread(ThreadGroup group, String threadName) {
 270         if (threadName == null) {
 271             throw new NullPointerException();
 272         }
 273 
 274         create(group, null, threadName, 0);
 275     }
 276 
 277     /**
 278      * Constructs a new {@code Thread} with a {@code Runnable} object, the given
 279      * name and belonging to the {@code ThreadGroup} passed as parameter.
 280      *
 281      * @param group
 282      *            {@code ThreadGroup} to which the new {@code Thread} will
 283      *            belong
 284      * @param runnable
 285      *            a {@code Runnable} whose method <code>run</code> will be
 286      *            executed by the new {@code Thread}
 287      * @param threadName
 288      *            the name for the {@code Thread} being created
 289      * @param stackSize
 290      *            a stack size for the new {@code Thread}. This has a highly
 291      *            platform-dependent interpretation. It may even be ignored
 292      *            completely.
 293      * @throws IllegalThreadStateException
 294      *             if <code>group.destroy()</code> has already been done
 295      * @see java.lang.ThreadGroup
 296      * @see java.lang.Runnable
 297      */
 298     public Thread(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
 299         if (threadName == null) {
 300             throw new NullPointerException();
 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 such
 310      * a thing (e.g. for Main).
 311      */
 312     Thread(ThreadGroup group, String name, int priority, boolean daemon) {
 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 their
 342      * work to.
 343      *
 344      * @param group ThreadGroup to which the new Thread will belong
 345      * @param runnable a java.lang.Runnable whose method <code>run</code> will
 346      *        be executed by the new Thread
 347      * @param threadName Name for the Thread being created
 348      * @param stackSize Platform dependent stack size
 349      * @throws IllegalThreadStateException if <code>group.destroy()</code> has
 350      *         already been done
 351      * @see java.lang.ThreadGroup
 352      * @see java.lang.Runnable
 353      */
 354     private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
 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 = new ThreadLocal.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 {@code Thread}s in the running {@code
 394      * Thread}'s group and its subgroups.
 395      *
 396      * @return the number of {@code Thread}s
 397      */
 398     public static int activeCount() {
 399         return currentThread().getThreadGroup().activeCount();
 400     }
 401 
 402     /**
 403      * Does nothing.
 404      */
 405     public final void checkAccess() {
 406     }
 407 
 408     /**
 409      * Returns the number of stack frames in this thread.
 410      *
 411      * @return Number of stack frames
 412      * @deprecated The results of this call were never well defined. To make
 413      *             things worse, it would depend on whether the Thread was
 414      *             suspended or not, and suspend was deprecated too.
 415      */
 416     @Deprecated
 417     public int countStackFrames() {
 418         return getStackTrace().length;
 419     }
 420 
 421     /**
 422      * Returns the Thread of the caller, that is, the current Thread.
 423      *
 424      * @return the current Thread.
 425      */
 426     public static Thread currentThread() {
 427         return VMThread.currentThread();
 428     }
 429 
 430     /**
 431      * Destroys the receiver without any monitor cleanup.
 432      *
 433      * @deprecated Not implemented.
 434      */
 435     @Deprecated
 436     public void destroy() {
 437         throw new NoSuchMethodError("Thread.destroy()"); // TODO Externalize???
 438     }
 439 
 440     /**
 441      * Prints to the standard error stream a text representation of the current
 442      * stack for this Thread.
 443      *
 444      * @see Throwable#printStackTrace()
 445      */
 446     public static void dumpStack() {
 447         new Throwable("stack dump").printStackTrace();
 448     }
 449 
 450     /**
 451      * Copies an array with all Threads which are in the same ThreadGroup as the
 452      * receiver - and subgroups - into the array <code>threads</code> passed as
 453      * parameter. If the array passed as parameter is too small no exception is
 454      * thrown - the extra elements are simply not copied.
 455      *
 456      * @param threads
 457      *            array into which the Threads will be copied
 458      * @return How many Threads were copied over
 459      */
 460     public static int enumerate(Thread[] threads) {
 461         Thread thread = Thread.currentThread();
 462         return thread.getThreadGroup().enumerate(threads);
 463     }
 464 
 465     /**
 466      * Returns a map of all the currently live threads to their stack traces.
 467      */
 468     public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
 469         Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>();
 470 
 471         // Find out how many live threads we have. Allocate a bit more
 472         // 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         return map;
 483     }
 484 
 485     /**
 486      * Returns the context ClassLoader for this Thread.
 487      *
 488      * @return ClassLoader The context ClassLoader
 489      * @see java.lang.ClassLoader
 490      * @see #getContextClassLoader()
 491      */
 492     public ClassLoader getContextClassLoader() {
 493         return contextClassLoader;
 494     }
 495 
 496     /**
 497      * Returns the default exception handler that's executed when uncaught
 498      * exception terminates a thread.
 499      *
 500      * @return an {@link UncaughtExceptionHandler} or <code>null</code> if
 501      *         none exists.
 502      */
 503     public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
 504         return defaultUncaughtHandler;
 505     }
 506 
 507     /**
 508      * Returns the thread's identifier. The ID is a positive <code>long</code>
 509      * generated on thread creation, is unique to the thread, and doesn't change
 510      * during the lifetime of the thread; the ID may be reused after the thread
 511      * has been terminated.
 512      *
 513      * @return the thread's ID.
 514      */
 515     public long getId() {
 516         return id;
 517     }
 518 
 519     /**
 520      * Returns the name of the Thread.
 521      *
 522      * @return the Thread's name
 523      */
 524     public final String getName() {
 525         return name;
 526     }
 527 
 528     /**
 529      * Returns the priority of the Thread.
 530      *
 531      * @return the Thread's priority
 532      * @see Thread#setPriority
 533      */
 534     public final int getPriority() {
 535         return priority;
 536     }
 537 
 538     /**
 539      * Returns an array of {@link StackTraceElement} representing the current thread's stack.
 540      */
 541     public StackTraceElement[] 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 for
 548      * monitoring purposes.
 549      *
 550      * @return a {@link State} value.
 551      */
 552     public State 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 code
 557         // 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                 return VMThread.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      * @return the Thread's ThreadGroup
 574      */
 575     public final ThreadGroup getThreadGroup() {
 576         // TODO This should actually be done at native termination.
 577         if (getState() == Thread.State.TERMINATED) {
 578             return null;
 579         } else {
 580             return group;
 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 <code>null</code> is returned.
 588      *
 589      * @return an {@link UncaughtExceptionHandler} instance or {@code null}.
 590      */
 591     public UncaughtExceptionHandler getUncaughtExceptionHandler() {
 592         if (uncaughtHandler != null)
 593             return uncaughtHandler;
 594         else
 595             return group;           // ThreadGroup is instance of UEH
 596     }
 597 
 598     /**
 599      * Posts an interrupt request to this {@code Thread}. The behavior depends on
 600      * the state of this {@code Thread}:
 601      * <ul>
 602      * <li>
 603      * {@code Thread}s blocked in one of {@code Object}'s {@code wait()} methods
 604      * or one of {@code Thread}'s {@code join()} or {@code sleep()} methods will
 605      * be woken up, their interrupt status will be cleared, and they receive an
 606      * {@link InterruptedException}.
 607      * <li>
 608      * {@code Thread}s blocked in an I/O operation of an
 609      * {@link java.nio.channels.InterruptibleChannel} will have their interrupt
 610      * status set and receive an
 611      * {@link java.nio.channels.ClosedByInterruptException}. Also, the channel
 612      * will be closed.
 613      * <li>
 614      * {@code Thread}s blocked in a {@link java.nio.channels.Selector} will have
 615      * their interrupt status set and return immediately. They don't receive an
 616      * exception in this case.
 617      * <ul>
 618      *
 619      * @see Thread#interrupted
 620      * @see Thread#isInterrupted
 621      */
 622     public void interrupt() {
 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 <code>boolean</code> indicating whether the current Thread (
 637      * <code>currentThread()</code>) has a pending interrupt request (<code>
 638      * true</code>) or not (<code>false</code>). It also has the side-effect of
 639      * clearing the flag.
 640      *
 641      * @return a <code>boolean</code> indicating the interrupt status
 642      * @see Thread#currentThread
 643      * @see Thread#interrupt
 644      * @see Thread#isInterrupted
 645      */
 646     public static boolean interrupted() {
 647         return VMThread.interrupted();
 648     }
 649 
 650     /**
 651      * Returns <code>true</code> if the receiver has already been started and
 652      * still runs code (hasn't died yet). Returns <code>false</code> either if
 653      * the receiver hasn't been started yet or if it has already started and run
 654      * to completion and died.
 655      *
 656      * @return a <code>boolean</code> indicating the liveness of the Thread
 657      * @see Thread#start
 658      */
 659     public final boolean isAlive() {
 660         return (vmThread != null);
 661     }
 662 
 663     /**
 664      * Returns a <code>boolean</code> indicating whether the receiver is a
 665      * daemon Thread (<code>true</code>) or not (<code>false</code>) A
 666      * 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 if
 668      * it had daemon Threads still running or not.
 669      *
 670      * @return a <code>boolean</code> indicating whether the Thread is a daemon
 671      * @see Thread#setDaemon
 672      */
 673     public final boolean isDaemon() {
 674         return daemon;
 675     }
 676 
 677     /**
 678      * Returns a <code>boolean</code> indicating whether the receiver has a
 679      * pending interrupt request (<code>true</code>) or not (
 680      * <code>false</code>)
 681      *
 682      * @return a <code>boolean</code> indicating the interrupt status
 683      * @see Thread#interrupt
 684      * @see Thread#interrupted
 685      */
 686     public boolean isInterrupted() {
 687         VMThread vmt = this.vmThread;
 688         if (vmt != null) {
 689             return vmt.isInterrupted();
 690         }
 691 
 692         return false;
 693     }
 694 
 695     /**
 696      * Blocks the current Thread (<code>Thread.currentThread()</code>) until
 697      * the receiver finishes its execution and dies.
 698      *
 699      * @throws InterruptedException if <code>interrupt()</code> was called for
 700      *         the receiver while it was in the <code>join()</code> call
 701      * @see Object#notifyAll
 702      * @see java.lang.ThreadDeath
 703      */
 704     public final void join() throws InterruptedException {
 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 (<code>Thread.currentThread()</code>) until
 719      * the receiver finishes its execution and dies or the specified timeout
 720      * expires, whatever happens first.
 721      *
 722      * @param millis The maximum time to wait (in milliseconds).
 723      * @throws InterruptedException if <code>interrupt()</code> was called for
 724      *         the receiver while it was in the <code>join()</code> call
 725      * @see Object#notifyAll
 726      * @see java.lang.ThreadDeath
 727      */
 728     public final void join(long millis) throws InterruptedException {
 729         join(millis, 0);
 730     }
 731 
 732     /**
 733      * Blocks the current Thread (<code>Thread.currentThread()</code>) until
 734      * the receiver finishes its execution and dies or the specified timeout
 735      * expires, whatever happens first.
 736      *
 737      * @param millis The maximum time to wait (in milliseconds).
 738      * @param nanos Extra nanosecond precision
 739      * @throws InterruptedException if <code>interrupt()</code> was called for
 740      *         the receiver while it was in the <code>join()</code> call
 741      * @see Object#notifyAll
 742      * @see java.lang.ThreadDeath
 743      */
 744     public final void join(long millis, int nanos) throws InterruptedException {
 745         if (millis < 0 || nanos < 0 || nanos >= NANOS_PER_MILLI) {
 746             throw new IllegalArgumentException();
 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 {@code UnsupportedOperationException}.
 790      *
 791      * @see Thread#suspend()
 792      * @deprecated Used with deprecated method {@link Thread#suspend}
 793      */
 794     @Deprecated
 795     public final void resume() {
 796         throw new UnsupportedOperationException();
 797     }
 798 
 799     /**
 800      * Calls the <code>run()</code> method of the Runnable object the receiver
 801      * holds. If no Runnable is set, does nothing.
 802      *
 803      * @see Thread#start
 804      */
 805     public void run() {
 806         if (target != null) {
 807             target.run();
 808         }
 809     }
 810 
 811     /**
 812      * Set the context ClassLoader for the receiver.
 813      *
 814      * @param cl The context ClassLoader
 815      * @see #getContextClassLoader()
 816      */
 817     public void setContextClassLoader(ClassLoader cl) {
 818         contextClassLoader = cl;
 819     }
 820 
 821     /**
 822      * Set if the receiver is a daemon Thread or not. This can only be done
 823      * before the Thread starts running.
 824      *
 825      * @param isDaemon
 826      *            indicates whether the Thread should be daemon or not
 827      * @see Thread#isDaemon
 828      */
 829     public final void setDaemon(boolean isDaemon) {
 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 in
 841      * case any Thread dies due to an unhandled exception.
 842      *
 843      * @param handler
 844      *            The handler to set or null.
 845      */
 846     public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
 847         Thread.defaultUncaughtHandler = handler;
 848     }
 849 
 850     /**
 851      * Adds a runnable to be invoked upon interruption. If this thread has
 852      * already been interrupted, the runnable will be invoked immediately. The
 853      * action should be idempotent as it may be invoked multiple times for a
 854      * single interruption.
 855      *
 856      * <p>Each call to this method must be matched with a corresponding call to
 857      * {@link #popInterruptAction$}.
 858      *
 859      * @hide used by NIO
 860      */
 861     public final void pushInterruptAction$(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 {@code interruptAction} so it is not invoked upon interruption.
 873      *
 874      * @param interruptAction the pushed action, used to check that the call
 875      *     stack is correctly nested.
 876      *
 877      * @hide used by NIO
 878      */
 879     public final void popInterruptAction$(Runnable interruptAction) {
 880         synchronized (interruptActions) {
 881             Runnable removed = interruptActions.remove(interruptActions.size() - 1);
 882             if (interruptAction != removed) {
 883                 throw new IllegalArgumentException(
 884                         "Expected " + interruptAction + " but was " + removed);
 885             }
 886         }
 887     }
 888 
 889     /**
 890      * Sets the name of the Thread.
 891      *
 892      * @param threadName the new name for the Thread
 893      * @see Thread#getName
 894      */
 895     public final void setName(String threadName) {
 896         if (threadName == null) {
 897             throw new NullPointerException();
 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 not
 910      * be the parameter that was passed - it will depend on the receiver's
 911      * ThreadGroup. The priority cannot be set to be higher than the receiver's
 912      * ThreadGroup's maxPriority().
 913      *
 914      * @param priority
 915      *            new priority for the Thread
 916      * @throws IllegalArgumentException
 917      *             if the new priority is greater than Thread.MAX_PRIORITY or
 918      *             less than Thread.MIN_PRIORITY
 919      * @see Thread#getPriority
 920      */
 921     public final void setPriority(int priority) {
 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      * <p>
 940      * Sets the uncaught exception handler. This handler is invoked in case this
 941      * Thread dies due to an unhandled exception.
 942      * </p>
 943      *
 944      * @param handler
 945      *            The handler to set or <code>null</code>.
 946      */
 947     public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
 948         uncaughtHandler = handler;
 949     }
 950 
 951     /**
 952      * Causes the thread which sent this message to sleep for the given interval
 953      * of time (given in milliseconds). The precision is not guaranteed - the
 954      * Thread may sleep more or less than requested.
 955      *
 956      * @param time
 957      *            The time to sleep in milliseconds.
 958      * @throws InterruptedException
 959      *             if <code>interrupt()</code> was called for this Thread while
 960      *             it was sleeping
 961      * @see Thread#interrupt()
 962      */
 963     public static void sleep(long time) throws InterruptedException {
 964         Thread.sleep(time, 0);
 965     }
 966 
 967     /**
 968      * Causes the thread which sent this message to sleep for the given interval
 969      * of time (given in milliseconds and nanoseconds). The precision is not
 970      * guaranteed - the Thread may sleep more or less than requested.
 971      *
 972      * @param millis
 973      *            The time to sleep in milliseconds.
 974      * @param nanos
 975      *            Extra nanosecond precision
 976      * @throws InterruptedException
 977      *             if <code>interrupt()</code> was called for this Thread while
 978      *             it was sleeping
 979      * @see Thread#interrupt()
 980      */
 981     public static void sleep(long millis, int nanos) throws InterruptedException {
 982         VMThread.sleep(millis, nanos);
 983     }
 984 
 985     /**
 986      * Starts the new Thread of execution. The <code>run()</code> method of
 987      * the receiver will be called by the receiver Thread itself (and not the
 988      * Thread calling <code>start()</code>).
 989      *
 990      * @throws IllegalThreadStateException if the Thread has been started before
 991      *
 992      * @see Thread#run
 993      */
 994     public synchronized void start() {
 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 is
1006      * resumed if it was suspended and awakened if it was sleeping, so that it
1007      * can proceed to throw ThreadDeath.
1008      *
1009      * @deprecated because stopping a thread in this manner is unsafe and can
1010      * leave your application and the VM in an unpredictable state.
1011      */
1012     @Deprecated
1013     public final void stop() {
1014         stop(new ThreadDeath());
1015     }
1016 
1017     /**
1018      * Throws {@code UnsupportedOperationException}.
1019      *
1020      * @throws NullPointerException if <code>throwable()</code> is
1021      *         <code>null</code>
1022      * @deprecated because stopping a thread in this manner is unsafe and can
1023      * leave your application and the VM in an unpredictable state.
1024      */
1025     @Deprecated
1026     public final synchronized void stop(Throwable throwable) {
1027         throw new UnsupportedOperationException();
1028     }
1029 
1030     /**
1031      * Throws {@code UnsupportedOperationException}.
1032      *
1033      * @see Thread#resume()
1034      * @deprecated May cause deadlocks.
1035      */
1036     @Deprecated
1037     public final void suspend() {
1038         throw new UnsupportedOperationException();
1039     }
1040 
1041     /**
1042      * Returns a string containing a concise, human-readable description of the
1043      * Thread. It includes the Thread's name, priority, and group name.
1044      *
1045      * @return a printable representation for the receiver.
1046      */
1047     @Override
1048     public String toString() {
1049         return "Thread[" + name + "," + priority + "," + group.getName() + "]";
1050     }
1051 
1052     /**
1053      * Causes the calling Thread to yield execution time to another Thread that
1054      * is ready to run. The actual scheduling is implementation-dependent.
1055      */
1056     public static void yield() {
1057         VMThread.yield();
1058     }
1059 
1060     /**
1061      * Indicates whether the current Thread has a monitor lock on the specified
1062      * object.
1063      *
1064      * @param object the object to test for the monitor lock
1065      * @return true if the current thread has a monitor lock on the specified
1066      *         object; false otherwise
1067      */
1068     public static boolean holdsLock(Object object) {
1069         return currentThread().vmThread.holdsLock(object);
1070     }
1071 
1072     /**
1073      * Implemented by objects that want to handle cases where a thread is being
1074      * terminated by an uncaught exception. Upon such termination, the handler
1075      * is notified of the terminating thread and causal exception. If there is
1076      * no explicit handler set then the thread's group is the default handler.
1077      */
1078     public static interface UncaughtExceptionHandler {
1079         /**
1080          * The thread is being terminated by an uncaught exception. Further
1081          * exceptions thrown in this method are prevent the remainder of the
1082          * method from executing, but are otherwise ignored.
1083          *
1084          * @param thread the thread that has an uncaught exception
1085          * @param ex the exception that was thrown
1086          */
1087         void uncaughtException(Thread thread, Throwable ex);
1088     }
1089 
1090     /**
1091      * Unparks this thread. This unblocks the thread it if it was
1092      * previously parked, or indicates that the thread is "preemptively
1093      * unparked" if it wasn't already parked. The latter means that the
1094      * next time the thread is told to park, it will merely clear its
1095      * latent park bit and carry on without blocking.
1096      *
1097      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
1098      * in-depth information of the behavior of this method.</p>
1099      *
1100      * @hide for Unsafe
1101      */
1102     public void unpark() {
1103         VMThread vmt = vmThread;
1104 
1105         if (vmt == null) {
1106             /*
1107              * vmThread is null before the thread is start()ed. In
1108              * this case, we just go ahead and set the state to
1109              * PREEMPTIVELY_UNPARKED. Since this happens before the
1110              * thread is started, we don't have to worry about
1111              * synchronizing with it.
1112              */
1113             parkState = ParkState.PREEMPTIVELY_UNPARKED;
1114             return;
1115         }
1116 
1117         synchronized (vmt) {
1118             switch (parkState) {
1119                 case ParkState.PREEMPTIVELY_UNPARKED: {
1120                     /*
1121                      * Nothing to do in this case: By definition, a
1122                      * preemptively unparked thread is to remain in
1123                      * the preemptively unparked state if it is told
1124                      * to unpark.
1125                      */
1126                     break;
1127                 }
1128                 case ParkState.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, or
1143      * indefinitely. If not indefinitely, this method unparks the thread
1144      * after the given number of nanoseconds if no other thread unparks it
1145      * first. If the thread has been "preemptively unparked," this method
1146      * cancels that unparking and returns immediately. This method may
1147      * also return spuriously (that is, without the thread being told to
1148      * unpark and without the indicated amount of time elapsing).
1149      *
1150      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
1151      * in-depth information of the behavior of this method.</p>
1152      *
1153      * <p>This method must only be called when <code>this</code> is the current
1154      * thread.
1155      *
1156      * @param nanos number of nanoseconds to park for or <code>0</code>
1157      * to park indefinitely
1158      * @throws IllegalArgumentException thrown if <code>nanos &lt; 0</code>
1159      *
1160      * @hide for Unsafe
1161      */
1162     public void parkFor(long nanos) {
1163         VMThread vmt = vmThread;
1164 
1165         if (vmt == null) {
1166             // Running threads should always have an associated vmThread.
1167             throw new AssertionError();
1168         }
1169 
1170         synchronized (vmt) {
1171             switch (parkState) {
1172                 case ParkState.PREEMPTIVELY_UNPARKED: {
1173                     parkState = ParkState.UNPARKED;
1174                     break;
1175                 }
1176                 case ParkState.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 become
1188                          * PREEMPTIVELY_UNPARKED before hitting this
1189                          * 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 new AssertionError(
1199                             "shouldn't happen: attempt to repark");
1200                 }
1201             }
1202         }
1203     }
1204 
1205     /**
1206      * Parks the current thread until the specified system time. This
1207      * method attempts to unpark the current thread immediately after
1208      * <code>System.currentTimeMillis()</code> reaches the specified
1209      * value, if no other thread unparks it first. If the thread has
1210      * been "preemptively unparked," this method cancels that
1211      * unparking and returns immediately. This method may also return
1212      * spuriously (that is, without the thread being told to unpark
1213      * and without the indicated amount of time elapsing).
1214      *
1215      * <p>See {@link java.util.concurrent.locks.LockSupport} for more
1216      * in-depth information of the behavior of this method.</p>
1217      *
1218      * <p>This method must only be called when <code>this</code> is the
1219      * current thread.
1220      *
1221      * @param time the time after which the thread should be unparked,
1222      * in absolute milliseconds-since-the-epoch
1223      *
1224      * @hide for Unsafe
1225      */
1226     public void parkUntil(long time) {
1227         VMThread vmt = vmThread;
1228 
1229         if (vmt == null) {
1230             // Running threads should always have an associated vmThread.
1231             throw new AssertionError();
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 that
1238              * the underlying system can only wait on monotonic time,
1239              * it is unclear if there is any way to avoid the
1240              * conflation. The downside here is that if, having
1241              * calculated the delay, the wall clock gets moved ahead,
1242              * this method may not return until well after the wall
1243              * clock has reached the originally designated time. The
1244              * reverse problem (the wall clock being turned back)
1245              * isn't a big deal, since this method is allowed to
1246              * spuriously return for any reason, and this situation
1247              * 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 }
View Code

Thread Localexpress

  1 /*
  2  * Copyright (C) 2008 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package java.lang;
 18 
 19 import java.lang.ref.Reference;
 20 import java.lang.ref.WeakReference;
 21 import java.util.concurrent.atomic.AtomicInteger;
 22 
 23 /**
 24  * Implements a thread-local storage, that is, a variable for which each thread
 25  * has its own value. All threads share the same {@code ThreadLocal} object,
 26  * but each sees a different value when accessing it, and changes made by one
 27  * thread do not affect the other threads. The implementation supports
 28  * {@code null} values.
 29  *
 30  * @see java.lang.Thread
 31  * @author Bob Lee
 32  */
 33 public class ThreadLocal<T> {
 34 
 35     /* Thanks to Josh Bloch and Doug Lea for code reviews and impl advice. */
 36 
 37     /**
 38      * Creates a new thread-local variable.
 39      */
 40     public ThreadLocal() {}
 41 
 42     /**
 43      * Returns the value of this variable for the current thread. If an entry
 44      * doesn't yet exist for this variable on this thread, this method will
 45      * create an entry, populating the value with the result of
 46      * {@link #initialValue()}.
 47      *
 48      * @return the current value of the variable for the calling thread.
 49      */
 50     @SuppressWarnings("unchecked")
 51     public T get() {
 52         // Optimized for the fast path.
 53         Thread currentThread = Thread.currentThread();
 54         Values values = values(currentThread);
 55         if (values != null) {
 56             Object[] table = values.table;
 57             int index = hash & values.mask;
 58             if (this.reference == table[index]) {
 59                 return (T) table[index + 1];
 60             }
 61         } else {
 62             values = initializeValues(currentThread);
 63         }
 64 
 65         return (T) values.getAfterMiss(this);
 66     }
 67 
 68     /**
 69      * Provides the initial value of this variable for the current thread.
 70      * The default implementation returns {@code null}.
 71      *
 72      * @return the initial value of the variable.
 73      */
 74     protected T initialValue() {
 75         return null;
 76     }
 77 
 78     /**
 79      * Sets the value of this variable for the current thread. If set to
 80      * {@code null}, the value will be set to null and the underlying entry will
 81      * still be present.
 82      *
 83      * @param value the new value of the variable for the caller thread.
 84      */
 85     public void set(T value) {
 86         Thread currentThread = Thread.currentThread();
 87         Values values = values(currentThread);
 88         if (values == null) {
 89             values = initializeValues(currentThread);
 90         }
 91         values.put(this, value);
 92     }
 93 
 94     /**
 95      * Removes the entry for this variable in the current thread. If this call
 96      * is followed by a {@link #get()} before a {@link #set},
 97      * {@code #get()} will call {@link #initialValue()} and create a new
 98      * entry with the resulting value.
 99      *
100      * @since 1.5
101      */
102     public void remove() {
103         Thread currentThread = Thread.currentThread();
104         Values values = values(currentThread);
105         if (values != null) {
106             values.remove(this);
107         }
108     }
109 
110     /**
111      * Creates Values instance for this thread and variable type.
112      */
113     Values initializeValues(Thread current) {
114         return current.localValues = new Values();
115     }
116 
117     /**
118      * Gets Values instance for this thread and variable type.
119      */
120     Values values(Thread current) {
121         return current.localValues;
122     }
123 
124     /** Weak reference to this thread local instance. */
125     private final Reference<ThreadLocal<T>> reference
126             = new WeakReference<ThreadLocal<T>>(this);
127 
128     /** Hash counter. */
129     private static AtomicInteger hashCounter = new AtomicInteger(0);
130 
131     /**
132      * Internal hash. We deliberately don't bother with #hashCode().
133      * Hashes must be even. This ensures that the result of
134      * (hash & (table.length - 1)) points to a key and not a value.
135      *
136      * We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
137      * every other bucket) to help prevent clustering.
138      */
139     private final int hash = hashCounter.getAndAdd(0x61c88647 * 2);
140 
141     /**
142      * Per-thread map of ThreadLocal instances to values.
143      */
144     static class Values {
145 
146         /**
147          * Size must always be a power of 2.
148          */
149         private static final int INITIAL_SIZE = 16;
150 
151         /**
152          * Placeholder for deleted entries.
153          */
154         private static final Object TOMBSTONE = new Object();
155 
156         /**
157          * Map entries. Contains alternating keys (ThreadLocal) and values.
158          * The length is always a power of 2.
159          */
160         private Object[] table;
161 
162         /** Used to turn hashes into indices. */
163         private int mask;
164 
165         /** Number of live entries. */
166         private int size;
167 
168         /** Number of tombstones. */
169         private int tombstones;
170 
171         /** Maximum number of live entries and tombstones. */
172         private int maximumLoad;
173 
174         /** Points to the next cell to clean up. */
175         private int clean;
176 
177         /**
178          * Constructs a new, empty instance.
179          */
180         Values() {
181             initializeTable(INITIAL_SIZE);
182             this.size = 0;
183             this.tombstones = 0;
184         }
185 
186         /**
187          * Used for InheritableThreadLocals.
188          */
189         Values(Values fromParent) {
190             this.table = fromParent.table.clone();
191             this.mask = fromParent.mask;
192             this.size = fromParent.size;
193             this.tombstones = fromParent.tombstones;
194             this.maximumLoad = fromParent.maximumLoad;
195             this.clean = fromParent.clean;
196             inheritValues(fromParent);
197         }
198 
199         /**
200          * Inherits values from a parent thread.
201          */
202         @SuppressWarnings({"unchecked"})
203         private void inheritValues(Values fromParent) {
204             // Transfer values from parent to child thread.
205             Object[] table = this.table;
206             for (int i = table.length - 2; i >= 0; i -= 2) {
207                 Object k = table[i];
208 
209                 if (k == null || k == TOMBSTONE) {
210                     // Skip this entry.
211                     continue;
212                 }
213 
214                 // The table can only contain null, tombstones and references.
215                 Reference<InheritableThreadLocal<?>> reference
216                         = (Reference<InheritableThreadLocal<?>>) k;
217                 // Raw type enables us to pass in an Object below.
218                 InheritableThreadLocal key = reference.get();
219                 if (key != null) {
220                     // Replace value with filtered value.
221                     // We should just let exceptions bubble out and tank
222                     // the thread creation
223                     table[i + 1] = key.childValue(fromParent.table[i + 1]);
224                 } else {
225                     // The key was reclaimed.
226                     table[i] = TOMBSTONE;
227                     table[i + 1] = null;
228                     fromParent.table[i] = TOMBSTONE;
229                     fromParent.table[i + 1] = null;
230 
231                     tombstones++;
232                     fromParent.tombstones++;
233 
234                     size--;
235                     fromParent.size--;
236                 }
237             }
238         }
239 
240         /**
241          * Creates a new, empty table with the given capacity.
242          */
243         private void initializeTable(int capacity) {
244             this.table = new Object[capacity * 2];
245             this.mask = table.length - 1;
246             this.clean = 0;
247             this.maximumLoad = capacity * 2 / 3; // 2/3
248         }
249 
250         /**
251          * Cleans up after garbage-collected thread locals.
252          */
253         private void cleanUp() {
254             if (rehash()) {
255                 // If we rehashed, we needn't clean up (clean up happens as
256                 // a side effect).
257                 return;
258             }
259 
260             if (size == 0) {
261                 // No live entries == nothing to clean.
262                 return;
263             }
264 
265             // Clean log(table.length) entries picking up where we left off
266             // last time.
267             int index = clean;
268             Object[] table = this.table;
269             for (int counter = table.length; counter > 0; counter >>= 1,
270                     index = next(index)) {
271                 Object k = table[index];
272 
273                 if (k == TOMBSTONE || k == null) {
274                     continue; // on to next entry
275                 }
276 
277                 // The table can only contain null, tombstones and references.
278                 @SuppressWarnings("unchecked")
279                 Reference<ThreadLocal<?>> reference
280                         = (Reference<ThreadLocal<?>>) k;
281                 if (reference.get() == null) {
282                     // This thread local was reclaimed by the garbage collector.
283                     table[index] = TOMBSTONE;
284                     table[index + 1] = null;
285                     tombstones++;
286                     size--;
287                 }
288             }
289 
290             // Point cursor to next index.
291             clean = index;
292         }
293 
294         /**
295          * Rehashes the table, expanding or contracting it as necessary.
296          * Gets rid of tombstones. Returns true if a rehash occurred.
297          * We must rehash every time we fill a null slot; we depend on the
298          * presence of null slots to end searches (otherwise, we'll infinitely
299          * loop).
300          */
301         private boolean rehash() {
302             if (tombstones + size < maximumLoad) {
303                 return false;
304             }
305 
306             int capacity = table.length >> 1;
307 
308             // Default to the same capacity. This will create a table of the
309             // same size and move over the live entries, analogous to a
310             // garbage collection. This should only happen if you churn a
311             // bunch of thread local garbage (removing and reinserting
312             // the same thread locals over and over will overwrite tombstones
313             // and not fill up the table).
314             int newCapacity = capacity;
315 
316             if (size > (capacity >> 1)) {
317                 // More than 1/2 filled w/ live entries.
318                 // Double size.
319                 newCapacity = capacity * 2;
320             }
321 
322             Object[] oldTable = this.table;
323 
324             // Allocate new table.
325             initializeTable(newCapacity);
326 
327             // We won't have any tombstones after this.
328             this.tombstones = 0;
329 
330             // If we have no live entries, we can quit here.
331             if (size == 0) {
332                 return true;
333             }
334 
335             // Move over entries.
336             for (int i = oldTable.length - 2; i >= 0; i -= 2) {
337                 Object k = oldTable[i];
338                 if (k == null || k == TOMBSTONE) {
339                     // Skip this entry.
340                     continue;
341                 }
342 
343                 // The table can only contain null, tombstones and references.
344                 @SuppressWarnings("unchecked")
345                 Reference<ThreadLocal<?>> reference
346                         = (Reference<ThreadLocal<?>>) k;
347                 ThreadLocal<?> key = reference.get();
348                 if (key != null) {
349                     // Entry is still live. Move it over.
350                     add(key, oldTable[i + 1]);
351                 } else {
352                     // The key was reclaimed.
353                     size--;
354                 }
355             }
356 
357             return true;
358         }
359 
360         /**
361          * Adds an entry during rehashing. Compared to put(), this method
362          * doesn't have to clean up, check for existing entries, account for
363          * tombstones, etc.
364          */
365         void add(ThreadLocal<?> key, Object value) {
366             for (int index = key.hash & mask;; index = next(index)) {
367                 Object k = table[index];
368                 if (k == null) {
369                     table[index] = key.reference;
370                     table[index + 1] = value;
371                     return;
372                 }
373             }
374         }
375 
376         /**
377          * Sets entry for given ThreadLocal to given value, creating an
378          * entry if necessary.
379          */
380         void put(ThreadLocal<?> key, Object value) {
381             cleanUp();
382 
383             // Keep track of first tombstone. That's where we want to go back
384             // and add an entry if necessary.
385             int firstTombstone = -1;
386 
387             for (int index = key.hash & mask;; index = next(index)) {
388                 Object k = table[index];
389 
390                 if (k == key.reference) {
391                     // Replace existing entry.
392                     table[index + 1] = value;
393                     return;
394                 }
395 
396                 if (k == null) {
397                     if (firstTombstone == -1) {
398                         // Fill in null slot.
399                         table[index] = key.reference;
400                         table[index + 1] = value;
401                         size++;
402                         return;
403                     }
404 
405                     // Go back and replace first tombstone.
406                     table[firstTombstone] = key.reference;
407                     table[firstTombstone + 1] = value;
408                     tombstones--;
409                     size++;
410                     return;
411                 }
412 
413                 // Remember first tombstone.
414                 if (firstTombstone == -1 && k == TOMBSTONE) {
415                     firstTombstone = index;
416                 }
417             }
418         }
419 
420         /**
421          * Gets value for given ThreadLocal after not finding it in the first
422          * slot.
423          */
424         Object getAfterMiss(ThreadLocal<?> key) {
425             Object[] table = this.table;
426             int index = key.hash & mask;
427 
428             // If the first slot is empty, the search is over.
429             if (table[index] == null) {
430                 Object value = key.initialValue();
431 
432                 // If the table is still the same and the slot is still empty...
433                 if (this.table == table && table[index] == null) {
434                     table[index] = key.reference;
435                     table[index + 1] = value;
436                     size++;
437 
438                     cleanUp();
439                     return value;
440                 }
441 
442                 // The table changed during initialValue().
443                 put(key, value);
444                 return value;
445             }
446 
447             // Keep track of first tombstone. That's where we want to go back
448             // and add an entry if necessary.
449             int firstTombstone = -1;
450 
451             // Continue search.
452             for (index = next(index);; index = next(index)) {
453                 Object reference = table[index];
454                 if (reference == key.reference) {
455                     return table[index + 1];
456                 }
457 
458                 // If no entry was found...
459                 if (reference == null) {
460                     Object value = key.initialValue();
461 
462                     // If the table is still the same...
463                     if (this.table == table) {
464                         // If we passed a tombstone and that slot still
465                         // contains a tombstone...
466                         if (firstTombstone > -1
467                                 && table[firstTombstone] == TOMBSTONE) {
468                             table[firstTombstone] = key.reference;
469                             table[firstTombstone + 1] = value;
470                             tombstones--;
471                             size++;
472 
473                             // No need to clean up here. We aren't filling
474                             // in a null slot.
475                             return value;
476                         }
477 
478                         // If this slot is still empty...
479                         if (table[index] == null) {
480                             table[index] = key.reference;
481                             table[index + 1] = value;
482                             size++;
483 
484                             cleanUp();
485                             return value;
486                         }
487                     }
488 
489                     // The table changed during initialValue().
490                     put(key, value);
491                     return value;
492                 }
493 
494                 if (firstTombstone == -1 && reference == TOMBSTONE) {
495                     // Keep track of this tombstone so we can overwrite it.
496                     firstTombstone = index;
497                 }
498             }
499         }
500 
501         /**
502          * Removes entry for the given ThreadLocal.
503          */
504         void remove(ThreadLocal<?> key) {
505             cleanUp();
506 
507             for (int index = key.hash & mask;; index = next(index)) {
508                 Object reference = table[index];
509 
510                 if (reference == key.reference) {
511                     // Success!
512                     table[index] = TOMBSTONE;
513                     table[index + 1] = null;
514                     tombstones++;
515                     size--;
516                     return;
517                 }
518 
519                 if (reference == null) {
520                     // No entry found.
521                     return;
522                 }
523             }
524         }
525 
526         /**
527          * Gets the next index. If we're at the end of the table, we wrap back
528          * around to 0.
529          */
530         private int next(int index) {
531             return (index + 2) & mask;
532         }
533     }
534 }
View Code

Thead Groupapache

  1 /*
  2  * Licensed to the Apache Software Foundation (ASF) under one or more
  3  * contributor license agreements.  See the NOTICE file distributed with
  4  * this work for additional information regarding copyright ownership.
  5  * The ASF licenses this file to You under the Apache License, Version 2.0
  6  * (the "License"); you may not use this file except in compliance with
  7  * the License.  You may obtain a copy of the License at
  8  *
  9  *     http://www.apache.org/licenses/LICENSE-2.0
 10  *
 11  * Unless required by applicable law or agreed to in writing, software
 12  * distributed under the License is distributed on an "AS IS" BASIS,
 13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  * See the License for the specific language governing permissions and
 15  * limitations under the License.
 16  */
 17 
 18 package java.lang;
 19 
 20 import java.lang.ref.WeakReference;
 21 import java.util.ArrayList;
 22 import java.util.Iterator;
 23 import java.util.List;
 24 import libcore.util.CollectionUtils;
 25 
 26 /**
 27  * {@code ThreadGroup} is a means of organizing threads into a hierarchical structure.
 28  * This class is obsolete. See <i>Effective Java</i> Item 73, "Avoid thread groups" for details.
 29  * @see Thread
 30  */
 31 public class ThreadGroup implements Thread.UncaughtExceptionHandler {
 32 
 33     // Name of this ThreadGroup
 34     // VM needs this field name for debugging.
 35     private String name;
 36 
 37     // Maximum priority for Threads inside this ThreadGroup
 38     private int maxPriority = Thread.MAX_PRIORITY;
 39 
 40     // The ThreadGroup to which this ThreadGroup belongs
 41     // VM needs this field name for debugging.
 42     final ThreadGroup parent;
 43 
 44     /**
 45      * Weak references to the threads in this group.
 46      * Access is guarded by synchronizing on this field.
 47      */
 48     private final List<WeakReference<Thread>> threadRefs = new ArrayList<WeakReference<Thread>>(5);
 49 
 50     /**
 51      * View of the threads.
 52      * Access is guarded by synchronizing on threadRefs.
 53      */
 54     private final Iterable<Thread> threads = CollectionUtils.dereferenceIterable(threadRefs, true);
 55 
 56     /**
 57      * Thread groups. Access is guarded by synchronizing on this field.
 58      */
 59     private final List<ThreadGroup> groups = new ArrayList<ThreadGroup>(3);
 60 
 61     // Whether this ThreadGroup is a daemon ThreadGroup or not
 62     private boolean isDaemon;
 63 
 64     // Whether this ThreadGroup has already been destroyed or not
 65     private boolean isDestroyed;
 66 
 67     /* the VM uses these directly; do not rename */
 68     static final ThreadGroup mSystem = new ThreadGroup();
 69     static final ThreadGroup mMain = new ThreadGroup(mSystem, "main");
 70 
 71     /**
 72      * Constructs a new {@code ThreadGroup} with the given name. The new {@code ThreadGroup}
 73      * will be child of the {@code ThreadGroup} to which the calling thread belongs.
 74      *
 75      * @param name the name
 76      * @see Thread#currentThread
 77      */
 78     public ThreadGroup(String name) {
 79         this(Thread.currentThread().getThreadGroup(), name);
 80     }
 81 
 82     /**
 83      * Constructs a new {@code ThreadGroup} with the given name, as a child of the
 84      * given {@code ThreadGroup}.
 85      *
 86      * @param parent the parent
 87      * @param name the name
 88      * @throws NullPointerException if {@code parent == null}
 89      * @throws IllegalThreadStateException if {@code parent} has been
 90      *         destroyed already
 91      */
 92     public ThreadGroup(ThreadGroup parent, String name) {
 93         if (parent == null) {
 94             throw new NullPointerException("parent == null");
 95         }
 96         this.name = name;
 97         this.parent = parent;
 98         if (parent != null) {
 99             parent.add(this);
100             this.setMaxPriority(parent.getMaxPriority());
101             if (parent.isDaemon()) {
102                 this.setDaemon(true);
103             }
104         }
105     }
106 
107     /**
108      * Initialize the special "system" ThreadGroup. Was "main" in Harmony,
109      * but we have an additional group above that in Android.
110      */
111     private ThreadGroup() {
112         this.name = "system";
113         this.parent = null;
114     }
115 
116     /**
117      * Returns the number of running {@code Thread}s which are children of this thread group,
118      * directly or indirectly.
119      *
120      * @return the number of children
121      */
122     public int activeCount() {
123         int count = 0;
124         synchronized (threadRefs) {
125             for (Thread thread : threads) {
126                 if (thread.isAlive()) {
127                     count++;
128                 }
129             }
130         }
131         synchronized (groups) {
132             for (ThreadGroup group : groups) {
133                 count += group.activeCount();
134             }
135         }
136         return count;
137     }
138 
139     /**
140      * Returns the number of {@code ThreadGroup}s which are children of this group,
141      * directly or indirectly.
142      *
143      * @return the number of children
144      */
145     public int activeGroupCount() {
146         int count = 0;
147         synchronized (groups) {
148             for (ThreadGroup group : groups) {
149                 // One for this group & the subgroups
150                 count += 1 + group.activeGroupCount();
151             }
152         }
153         return count;
154     }
155 
156     /**
157      * Adds a {@code ThreadGroup} to this thread group.
158      *
159      * @param g ThreadGroup to add
160      * @throws IllegalThreadStateException if this group has been destroyed already
161      */
162     private void add(ThreadGroup g) throws IllegalThreadStateException {
163         synchronized (groups) {
164             if (isDestroyed) {
165                 throw new IllegalThreadStateException();
166             }
167             groups.add(g);
168         }
169     }
170 
171     /**
172      * Does nothing. The definition of this method depends on the deprecated
173      * method {@link #suspend()}. The exact behavior of this call was never
174      * specified.
175      *
176      * @param b Used to control low memory implicit suspension
177      * @return {@code true} (always)
178      *
179      * @deprecated Required deprecated method suspend().
180      */
181     @Deprecated
182     public boolean allowThreadSuspension(boolean b) {
183         // Does not apply to this VM, no-op
184         return true;
185     }
186 
187     /**
188      * Does nothing.
189      */
190     public final void checkAccess() {
191     }
192 
193     /**
194      * Destroys this thread group and recursively all its subgroups. It is only legal
195      * to destroy a {@code ThreadGroup} that has no threads in it. Any daemon
196      * {@code ThreadGroup} is destroyed automatically when it becomes empty (no threads
197      * or thread groups in it).
198      *
199      * @throws IllegalThreadStateException if this thread group or any of its
200      *         subgroups has been destroyed already or if it still contains
201      *         threads.
202      */
203     public final void destroy() {
204         synchronized (threadRefs) {
205             synchronized (groups) {
206                 if (isDestroyed) {
207                     throw new IllegalThreadStateException(
208                             "Thread group was already destroyed: "
209                             + (this.name != null ? this.name : "n/a"));
210                 }
211                 if (threads.iterator().hasNext()) {
212                     throw new IllegalThreadStateException(
213                             "Thread group still contains threads: "
214                             + (this.name != null ? this.name : "n/a"));
215                 }
216                 // Call recursively for subgroups
217                 while (!groups.isEmpty()) {
218                     // We always get the first element - remember, when the
219                     // child dies it removes itself from our collection. See
220                     // below.
221                     groups.get(0).destroy();
222                 }
223 
224                 if (parent != null) {
225                     parent.remove(this);
226                 }
227 
228                 // Now that the ThreadGroup is really destroyed it can be tagged as so
229                 this.isDestroyed = true;
230             }
231         }
232     }
233 
234     /*
235      * Auxiliary method that destroys this thread group and recursively all its
236      * subgroups if this is a daemon ThreadGroup.
237      *
238      * @see #destroy
239      * @see #setDaemon
240      * @see #isDaemon
241      */
242     private void destroyIfEmptyDaemon() {
243         // Has to be non-destroyed daemon to make sense
244         synchronized (threadRefs) {
245             if (isDaemon && !isDestroyed && !threads.iterator().hasNext()) {
246                 synchronized (groups) {
247                     if (groups.isEmpty()) {
248                         destroy();
249                     }
250                 }
251             }
252         }
253     }
254 
255     /**
256      * Iterates over all active threads in this group (and its sub-groups) and
257      * stores the threads in the given array. Returns when the array is full or
258      * no more threads remain, whichever happens first.
259      *
260      * <p>Note that this method will silently ignore any threads that don't fit in the
261      * supplied array.
262      *
263      * @param threads the array into which the {@code Thread}s will be copied
264      * @return the number of {@code Thread}s that were copied
265      */
266     public int enumerate(Thread[] threads) {
267         return enumerate(threads, true);
268     }
269 
270     /**
271      * Iterates over all active threads in this group (and, optionally, its
272      * sub-groups) and stores the threads in the given array. Returns when the
273      * array is full or no more threads remain, whichever happens first.
274      *
275      * <p>Note that this method will silently ignore any threads that don't fit in the
276      * supplied array.
277      *
278      * @param threads the array into which the {@code Thread}s will be copied
279      * @param recurse indicates whether {@code Thread}s in subgroups should be
280      *        recursively copied as well
281      * @return the number of {@code Thread}s that were copied
282      */
283     public int enumerate(Thread[] threads, boolean recurse) {
284         return enumerateGeneric(threads, recurse, 0, true);
285     }
286 
287     /**
288      * Iterates over all thread groups in this group (and its sub-groups) and
289      * and stores the groups in the given array. Returns when the array is full
290      * or no more groups remain, whichever happens first.
291      *
292      * <p>Note that this method will silently ignore any thread groups that don't fit in the
293      * supplied array.
294      *
295      * @param groups the array into which the {@code ThreadGroup}s will be copied
296      * @return the number of {@code ThreadGroup}s that were copied
297      */
298     public int enumerate(ThreadGroup[] groups) {
299         return enumerate(groups, true);
300     }
301 
302     /**
303      * Iterates over all thread groups in this group (and, optionally, its
304      * sub-groups) and stores the groups in the given array. Returns when
305      * the array is full or no more groups remain, whichever happens first.
306      *
307      * <p>Note that this method will silently ignore any thread groups that don't fit in the
308      * supplied array.
309      *
310      * @param groups the array into which the {@code ThreadGroup}s will be copied
311      * @param recurse indicates whether {@code ThreadGroup}s in subgroups should be
312      *        recursively copied as well or not
313      * @return the number of {@code ThreadGroup}s that were copied
314      */
315     public int enumerate(ThreadGroup[] groups, boolean recurse) {
316         return enumerateGeneric(groups, recurse, 0, false);
317     }
318 
319     /**
320      * Copies into <param>enumeration</param> starting at
321      * <param>enumerationIndex</param> all Threads or ThreadGroups in the
322      * receiver. If <param>recurse</param> is true, recursively enumerate the
323      * elements in subgroups.
324      *
325      * If the array passed as parameter is too small no exception is thrown -
326      * the extra elements are simply not copied.
327      *
328      * @param enumeration array into which the elements will be copied
329      * @param recurse Indicates whether subgroups should be enumerated or not
330      * @param enumerationIndex Indicates in which position of the enumeration
331      *        array we are
332      * @param enumeratingThreads Indicates whether we are enumerating Threads or
333      *        ThreadGroups
334      * @return How many elements were enumerated/copied over
335      */
336     private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
337             boolean enumeratingThreads) {
338         if (enumeratingThreads) {
339             synchronized (threadRefs) {
340                 // walk the references directly so we can iterate in reverse order
341                 for (int i = threadRefs.size() - 1; i >= 0; --i) {
342                     Thread thread = threadRefs.get(i).get();
343                     if (thread != null && thread.isAlive()) {
344                         if (enumerationIndex >= enumeration.length) {
345                             return enumerationIndex;
346                         }
347                         enumeration[enumerationIndex++] = thread;
348                     }
349                 }
350             }
351         } else {
352             synchronized (groups) {
353                 for (int i = groups.size() - 1; i >= 0; --i) {
354                     if (enumerationIndex >= enumeration.length) {
355                         return enumerationIndex;
356                     }
357                     enumeration[enumerationIndex++] = groups.get(i);
358                 }
359             }
360         }
361 
362         if (recurse) {
363             synchronized (groups) {
364                 for (ThreadGroup group : groups) {
365                     if (enumerationIndex >= enumeration.length) {
366                         return enumerationIndex;
367                     }
368                     enumerationIndex = group.enumerateGeneric(enumeration, recurse,
369                             enumerationIndex, enumeratingThreads);
370                 }
371             }
372         }
373         return enumerationIndex;
374     }
375 
376     /**
377      * Returns the maximum allowed priority for a {@code Thread} in this thread group.
378      *
379      * @return the maximum priority
380      *
381      * @see #setMaxPriority
382      */
383     public final int getMaxPriority() {
384         return maxPriority;
385     }
386 
387     /**
388      * Returns the name of this thread group.
389      *
390      * @return the group's name
391      */
392     public final String getName() {
393         return name;
394     }
395 
396     /**
397      * Returns this thread group's parent {@code ThreadGroup}. It can be null if this
398      * is the the root ThreadGroup.
399      *
400      * @return the parent
401      */
402     public final ThreadGroup getParent() {
403         return parent;
404     }
405 
406     /**
407      * Interrupts every {@code Thread} in this group and recursively in all its
408      * subgroups.
409      *
410      * @see Thread#interrupt
411      */
412     public final void interrupt() {
413         synchronized (threadRefs) {
414             for (Thread thread : threads) {
415                 thread.interrupt();
416             }
417         }
418         synchronized (groups) {
419             for (ThreadGroup group : groups) {
420                 group.interrupt();
421             }
422         }
423     }
424 
425     /**
426      * Checks whether this thread group is a daemon {@code ThreadGroup}.
427      *
428      * @return true if this thread group is a daemon {@code ThreadGroup}
429      *
430      * @see #setDaemon
431      * @see #destroy
432      */
433     public final boolean isDaemon() {
434         return isDaemon;
435     }
436 
437     /**
438      * Checks whether this thread group has already been destroyed.
439      *
440      * @return true if this thread group has already been destroyed
441      * @see #destroy
442      */
443     public synchronized boolean isDestroyed() {
444         return isDestroyed;
445     }
446 
447     /**
448      * Outputs to {@code System.out} a text representation of the
449      * hierarchy of {@code Thread}s and {@code ThreadGroup}s in this thread group (and recursively).
450      * Proper indentation is used to show the nesting of groups inside groups
451      * and threads inside groups.
452      */
453     public void list() {
454         // We start in a fresh line
455         System.out.println();
456         list(0);
457     }
458 
459     /*
460      * Outputs to {@code System.out}a text representation of the
461      * hierarchy of Threads and ThreadGroups in this thread group (and recursively).
462      * The indentation will be four spaces per level of nesting.
463      *
464      * @param levels How many levels of nesting, so that proper indentation can
465      * be output.
466      */
467     private void list(int levels) {
468         indent(levels);
469         System.out.println(this.toString());
470 
471         ++levels;
472         synchronized (threadRefs) {
473             for (Thread thread : threads) {
474                 indent(levels);
475                 System.out.println(thread);
476             }
477         }
478         synchronized (groups) {
479             for (ThreadGroup group : groups) {
480                 group.list(levels);
481             }
482         }
483     }
484 
485     private void indent(int levels) {
486         for (int i = 0; i < levels; i++) {
487             System.out.print("    "); // 4 spaces for each level
488         }
489     }
490 
491     /**
492      * Checks whether this thread group is a direct or indirect parent group of a
493      * given {@code ThreadGroup}.
494      *
495      * @param g the potential child {@code ThreadGroup}
496      * @return true if this thread group is parent of {@code g}
497      */
498     public final boolean parentOf(ThreadGroup g) {
499         while (g != null) {
500             if (this == g) {
501                 return true;
502             }
503             g = g.parent;
504         }
505         return false;
506     }
507 
508     /**
509      * Removes an immediate subgroup.
510      *
511      * @param g ThreadGroup to remove
512      *
513      * @see #add(Thread)
514      * @see #add(ThreadGroup)
515      */
516     private void remove(ThreadGroup g) {
517         synchronized (groups) {
518             for (Iterator<ThreadGroup> i = groups.iterator(); i.hasNext(); ) {
519                 ThreadGroup threadGroup = i.next();
520                 if (threadGroup.equals(g)) {
521                     i.remove();
522                     break;
523                 }
524             }
525         }
526         destroyIfEmptyDaemon();
527     }
528 
529     /**
530      * Resumes every thread in this group and recursively in all its
531      * subgroups.
532      *
533      * @see Thread#resume
534      * @see #suspend
535      *
536      * @deprecated Requires deprecated method Thread.resume().
537      */
538     @SuppressWarnings("deprecation")
539     @Deprecated
540     public final void resume() {
541         synchronized (threadRefs) {
542             for (Thread thread : threads) {
543                 thread.resume();
544             }
545         }
546         synchronized (groups) {
547             for (ThreadGroup group : groups) {
548                 group.resume();
549             }
550         }
551     }
552 
553     /**
554      * Sets whether this is a daemon {@code ThreadGroup} or not. Daemon
555      * thread groups are automatically destroyed when they become empty.
556      *
557      * @param isDaemon the new value
558      * @see #isDaemon
559      * @see #destroy
560      */
561     public final void setDaemon(boolean isDaemon) {
562         this.isDaemon = isDaemon;
563     }
564 
565     /**
566      * Configures the maximum allowed priority for a {@code Thread} in this group and
567      * recursively in all its subgroups.
568      *
569      * <p>A caller can never increase the maximum priority of a thread group.
570      * Such an attempt will not result in an exception, it will
571      * simply leave the thread group with its current maximum priority.
572      *
573      * @param newMax the new maximum priority to be set
574      *
575      * @throws IllegalArgumentException if the new priority is greater than
576      *         Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
577      *
578      * @see #getMaxPriority
579      */
580     public final void setMaxPriority(int newMax) {
581         if (newMax <= this.maxPriority) {
582             if (newMax < Thread.MIN_PRIORITY) {
583                 newMax = Thread.MIN_PRIORITY;
584             }
585 
586             int parentPriority = parent == null ? newMax : parent.getMaxPriority();
587             this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
588             synchronized (groups) {
589                 for (ThreadGroup group : groups) {
590                     group.setMaxPriority(newMax);
591                 }
592             }
593         }
594     }
595 
596     /**
597      * Stops every thread in this group and recursively in all its subgroups.
598      *
599      * @see Thread#stop()
600      * @see Thread#stop(Throwable)
601      * @see ThreadDeath
602      *
603      * @deprecated Requires deprecated method Thread.stop().
604      */
605     @SuppressWarnings("deprecation")
606     @Deprecated
607     public final void stop() {
608         if (stopHelper()) {
609             Thread.currentThread().stop();
610         }
611     }
612 
613     @SuppressWarnings("deprecation")
614     private boolean stopHelper() {
615         boolean stopCurrent = false;
616         synchronized (threadRefs) {
617             Thread current = Thread.currentThread();
618             for (Thread thread : threads) {
619                 if (thread == current) {
620                     stopCurrent = true;
621                 } else {
622                     thread.stop();
623                 }
624             }
625         }
626         synchronized (groups) {
627             for (ThreadGroup group : groups) {
628                 stopCurrent |= group.stopHelper();
629             }
630         }
631         return stopCurrent;
632     }
633 
634     /**
635      * Suspends every thread in this group and recursively in all its
636      * subgroups.
637      *
638      * @see Thread#suspend
639      * @see #resume
640      *
641      * @deprecated Requires deprecated method Thread.suspend().
642      */
643     @SuppressWarnings("deprecation")
644     @Deprecated
645     public final void suspend() {
646         if (suspendHelper()) {
647             Thread.currentThread().suspend();
648         }
649     }
650 
651     @SuppressWarnings("deprecation")
652     private boolean suspendHelper() {
653         boolean suspendCurrent = false;
654         synchronized (threadRefs) {
655             Thread current = Thread.currentThread();
656             for (Thread thread : threads) {
657                 if (thread == current) {
658                     suspendCurrent = true;
659                 } else {
660                     thread.suspend();
661                 }
662             }
663         }
664         synchronized (groups) {
665             for (ThreadGroup group : groups) {
666                 suspendCurrent |= group.suspendHelper();
667             }
668         }
669         return suspendCurrent;
670     }
671 
672     @Override
673     public String toString() {
674         return getClass().getName() + "[name=" + getName()
675                 + ",maxPriority=" + getMaxPriority() + "]";
676     }
677 
678     /**
679      * Handles uncaught exceptions. Any uncaught exception in any {@code Thread}
680      * is forwarded to the thread's {@code ThreadGroup} by invoking this
681      * method.
682      *
683      * <p>New code should use {@link Thread#setUncaughtExceptionHandler} instead of thread groups.
684      *
685      * @param t the Thread that terminated with an uncaught exception
686      * @param e the uncaught exception itself
687      */
688     public void uncaughtException(Thread t, Throwable e) {
689         if (parent != null) {
690             parent.uncaughtException(t, e);
691         } else if (Thread.getDefaultUncaughtExceptionHandler() != null) {
692             // TODO The spec is unclear regarding this. What do we do?
693             Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, e);
694         } else if (!(e instanceof ThreadDeath)) {
695             // No parent group, has to be 'system' Thread Group
696             e.printStackTrace(System.err);
697         }
698     }
699 
700     /**
701      * Called by the Thread constructor.
702      */
703     final void addThread(Thread thread) throws IllegalThreadStateException {
704         synchronized (threadRefs) {
705             if (isDestroyed) {
706                 throw new IllegalThreadStateException();
707             }
708             threadRefs.add(new WeakReference<Thread>(thread));
709         }
710     }
711 
712     /**
713      * Called by the VM when a Thread dies.
714      */
715     final void removeThread(Thread thread) throws IllegalThreadStateException {
716         synchronized (threadRefs) {
717             for (Iterator<Thread> i = threads.iterator(); i.hasNext(); ) {
718                 if (i.next().equals(thread)) {
719                     i.remove();
720                     break;
721                 }
722             }
723         }
724         destroyIfEmptyDaemon();
725     }
726 }
View Code

 VMThread編程

  1 /* VMThread -- VM interface for Thread of executable code
  2    Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation
  3 
  4 This file is part of GNU Classpath.
  5 
  6 GNU Classpath is free software; you can redistribute it and/or modify
  7 it under the terms of the GNU General Public License as published by
  8 the Free Software Foundation; either version 2, or (at your option)
  9 any later version.
 10 
 11 GNU Classpath is distributed in the hope that it will be useful, but
 12 WITHOUT ANY WARRANTY; without even the implied warranty of
 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14 General Public License for more details.
 15 
 16 You should have received a copy of the GNU General Public License
 17 along with GNU Classpath; see the file COPYING.  If not, write to the
 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 19 02110-1301 USA.
 20 
 21 Linking this library statically or dynamically with other modules is
 22 making a combined work based on this library.  Thus, the terms and
 23 conditions of the GNU General Public License cover the whole
 24 combination.
 25 
 26 As a special exception, the copyright holders of this library give you
 27 permission to link this library with independent modules to produce an
 28 executable, regardless of the license terms of these independent
 29 modules, and to copy and distribute the resulting executable under
 30 terms of your choice, provided that you also meet, for each linked
 31 independent module, the terms and conditions of the license of that
 32 module.  An independent module is a module which is not derived from
 33 or based on this library.  If you modify this library, you may extend
 34 this exception to your version of the library, but you are not
 35 obligated to do so.  If you do not wish to do so, delete this
 36 exception statement from your version. */
 37 
 38 package java.lang;
 39 
 40 /**
 41  * VM interface for Thread of executable code. Holds VM dependent state.
 42  * It is deliberately package local and final and should only be accessed
 43  * by the Thread class.
 44  * <p>
 45  * This is the GNU Classpath reference implementation, it should be adapted
 46  * for a specific VM.
 47  * <p>
 48  * The following methods must be implemented:
 49  * <ul>
 50  * <li>native void start(long stacksize);
 51  * <li>native void interrupt();
 52  * <li>native boolean isInterrupted();
 53  * <li>native void suspend();
 54  * <li>native void resume();
 55  * <li>native void nativeSetPriority(int priority);
 56  * <li>native void nativeStop(Throwable t);
 57  * <li>native static Thread currentThread();
 58  * <li>static native void yield();
 59  * <li>static native boolean interrupted();
 60  * </ul>
 61  * All other methods may be implemented to make Thread handling more efficient
 62  * or to implement some optional (and sometimes deprecated) behaviour. Default
 63  * implementations are provided but it is highly recommended to optimize them
 64  * for a specific VM.
 65  * 
 66  * @author Jeroen Frijters (jeroen@frijters.net)
 67  * @author Dalibor Topic (robilad@kaffe.org)
 68  */
 69 final class VMThread
 70 {
 71     /**
 72      * The Thread object that this VM state belongs to.
 73      * Used in currentThread() and start().
 74      * Note: when this thread dies, this reference is *not* cleared
 75      */
 76     volatile Thread thread;
 77 
 78     /**
 79      * Flag that is set when the thread runs, used by stop() to protect against
 80      * stop's getting lost.
 81      */
 82     private volatile boolean running;
 83 
 84     /**
 85      * VM private data.
 86      */
 87     private transient Object vmdata;
 88 
 89     /**
 90      * Private constructor, create VMThreads with the static create method.
 91      *
 92      * @param thread The Thread object that was just created.
 93      */
 94     private VMThread(Thread thread)
 95     {
 96     this.thread = thread;
 97     }
 98 
 99     /**
100      * This method is the initial Java code that gets executed when a native
101      * thread starts. It's job is to coordinate with the rest of the VMThread
102      * logic and to start executing user code and afterwards handle clean up.
103      */
104     private void run()
105     {
106     try
107     {
108         try
109         {
110         running = true;
111         synchronized(thread)
112         {
113             Throwable t = thread.stillborn;
114             if(t != null)
115             {
116             thread.stillborn = null;
117             throw t;
118             }
119         }
120         thread.run();
121         }
122         catch(Throwable t)
123         {
124         try
125         {
126           Thread.UncaughtExceptionHandler handler;
127           handler = thread.getUncaughtExceptionHandler();
128           handler.uncaughtException(thread, t);
129         }
130         catch(Throwable ignore)
131         {
132         }
133         }
134     }
135     finally
136     {
137         // Setting runnable to false is partial protection against stop
138         // being called while we're cleaning up. To be safe all code in
139         // VMThread be unstoppable.
140         running = false;
141         thread.die();
142         synchronized(this)
143         {
144         // release the threads waiting to join us
145         notifyAll();
146         }
147     }
148     }
149 
150     /**
151      * Creates a native Thread. This is called from the start method of Thread.
152      * The Thread is started.
153      *
154      * @param thread The newly created Thread object
155      * @param stacksize Indicates the requested stacksize. Normally zero,
156      * non-zero values indicate requested stack size in bytes but it is up
157      * to the specific VM implementation to interpret them and may be ignored.
158      */
159     static void create(Thread thread, long stacksize)
160     {
161     VMThread vmThread = new VMThread(thread);
162     vmThread.start(stacksize);
163     thread.vmThread = vmThread;
164     }
165 
166     /**
167      * Gets the name of the thread. Usually this is the name field of the
168      * associated Thread object, but some implementation might choose to
169      * return the name of the underlying platform thread.
170      */
171     String getName()
172     {
173     return thread.name;
174     }
175 
176     /**
177      * Set the name of the thread. Usually this sets the name field of the
178      * associated Thread object, but some implementations might choose to
179      * set the name of the underlying platform thread.
180      * @param name The new name
181      */
182     void setName(String name)
183     {
184     thread.name = name;
185     }
186 
187     /**
188      * Set the thread priority field in the associated Thread object and
189      * calls the native method to set the priority of the underlying
190      * platform thread.
191      * @param priority The new priority
192      */
193     void setPriority(int priority)
194     {
195     thread.priority = priority;
196     nativeSetPriority(priority);
197     }
198 
199     /**
200      * Returns the priority. Usually this is the priority field from the
201      * associated Thread object, but some implementation might choose to
202      * return the priority of the underlying platform thread.
203      * @return this Thread's priority
204      */
205     int getPriority()
206     {
207         return thread.priority;
208     }
209 
210     /**
211      * Returns true if the thread is a daemon thread. Usually this is the
212      * daemon field from the associated Thread object, but some
213      * implementation might choose to return the daemon state of the underlying
214      * platform thread.
215      * @return whether this is a daemon Thread or not
216      */
217     boolean isDaemon()
218     {
219         return thread.daemon;
220     }
221 
222     /**
223      * Returns the number of stack frames in this Thread.
224      * Will only be called when when a previous call to suspend() returned true.
225      *
226      * @deprecated unsafe operation
227      */
228     native int countStackFrames();
229 
230     /**
231      * Wait the specified amount of time for the Thread in question to die.
232      *
233      * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
234      * not offer that fine a grain of timing resolution. Besides, there is
235      * no guarantee that this thread can start up immediately when time expires,
236      * because some other thread may be active.  So don't expect real-time
237      * performance.
238      *
239      * @param ms the number of milliseconds to wait, or 0 for forever
240      * @param ns the number of extra nanoseconds to sleep (0-999999)
241      * @throws InterruptedException if the Thread is interrupted; it's
242      *         <i>interrupted status</i> will be cleared
243      */
244     synchronized void join(long ms, int ns) throws InterruptedException
245     {
246     // Round up
247     ms += (ns != 0) ? 1 : 0;
248 
249     // Compute end time, but don't overflow
250     long now = System.currentTimeMillis();
251     long end = now + ms;
252     if (end < now)
253         end = Long.MAX_VALUE;
254 
255     // A VM is allowed to return from wait() without notify() having been
256     // called, so we loop to handle possible spurious wakeups.
257     while(thread.vmThread != null)
258     {
259         // We use the VMThread object to wait on, because this is a private
260         // object, so client code cannot call notify on us.
261         wait(ms);
262         if(ms != 0)
263         {
264         now = System.currentTimeMillis();
265         ms = end - now;
266         if(ms <= 0)
267         {
268             break;
269         }
270         }
271     }
272     }
273 
274     /**
275      * Cause this Thread to stop abnormally and throw the specified exception.
276      * If you stop a Thread that has not yet started, the stop is ignored
277      * (contrary to what the JDK documentation says).
278      * <b>WARNING</b>This bypasses Java security, and can throw a checked
279      * exception which the call stack is unprepared to handle. Do not abuse 
280      * this power.
281      *
282      * <p>This is inherently unsafe, as it can interrupt synchronized blocks and
283      * leave data in bad states.
284      *
285      * <p><b>NOTE</b> stop() should take care not to stop a thread if it is
286      * executing code in this class.
287      *
288      * @param t the Throwable to throw when the Thread dies
289      * @deprecated unsafe operation, try not to use
290      */
291     void stop(Throwable t)
292     {
293     // Note: we assume that we own the lock on thread
294     // (i.e. that Thread.stop() is synchronized)
295     if(running)
296         nativeStop(t);
297     else
298         thread.stillborn = t;
299     }
300 
301     /**
302      * Create a native thread on the underlying platform and start it executing
303      * on the run method of this object.
304      * @param stacksize the requested size of the native thread stack
305      */
306     native void start(long stacksize);
307 
308     /**
309      * Interrupt this thread.
310      */
311     native void interrupt();
312 
313     /**
314      * Determine whether this Thread has been interrupted, but leave
315      * the <i>interrupted status</i> alone in the process.
316      *
317      * @return whether the Thread has been interrupted
318      */
319     native boolean isInterrupted();
320 
321     /**
322      * Suspend this Thread.  It will not come back, ever, unless it is resumed.
323      */
324     native void suspend();
325 
326     /**
327      * Resume this Thread.  If the thread is not suspended, this method does
328      * nothing.
329      */
330     native void resume();
331 
332     /**
333      * Set the priority of the underlying platform thread.
334      *
335      * @param priority the new priority
336      */
337     native void nativeSetPriority(int priority);
338 
339     /**
340      * Asynchronously throw the specified throwable in this Thread.
341      *
342      * @param t the exception to throw
343      */
344     native void nativeStop(Throwable t);
345 
346     /**
347      * Return the Thread object associated with the currently executing
348      * thread.
349      *
350      * @return the currently executing Thread
351      */
352     static native Thread currentThread();
353 
354     /**
355      * Yield to another thread. The Thread will not lose any locks it holds
356      * during this time. There are no guarantees which thread will be
357      * next to run, and it could even be this one, but most VMs will choose
358      * the highest priority thread that has been waiting longest.
359      */
360     static native void yield();
361 
362     /**
363      * Suspend the current Thread's execution for the specified amount of
364      * time. The Thread will not lose any locks it has during this time. There
365      * are no guarantees which thread will be next to run, but most VMs will
366      * choose the highest priority thread that has been waiting longest.
367      *
368      * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
369      * not offer that fine a grain of timing resolution. Besides, there is
370      * no guarantee that this thread can start up immediately when time expires,
371      * because some other thread may be active.  So don't expect real-time
372      * performance.
373      *
374      * @param ms the number of milliseconds to sleep.
375      * @param ns the number of extra nanoseconds to sleep (0-999999)
376      * @throws InterruptedException if the Thread is (or was) interrupted;
377      *         it's <i>interrupted status</i> will be cleared
378      */
379     static void sleep(long ms, int ns) throws InterruptedException
380     {
381       // Note: JDK treats a zero length sleep is like Thread.yield(),
382       // without checking the interrupted status of the thread.
383       // It's unclear if this is a bug in the implementation or the spec.
384       // See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6213203
385       if (ms == 0 && ns == 0)
386     {
387       if (Thread.interrupted())
388         throw new InterruptedException();
389       return;
390     }
391 
392       // Compute end time, but don't overflow
393       long now = System.currentTimeMillis();
394       long end = now + ms;
395       if (end < now)
396       end = Long.MAX_VALUE;
397 
398       // A VM is allowed to return from wait() without notify() having been
399       // called, so we loop to handle possible spurious wakeups.
400       VMThread vt = Thread.currentThread().vmThread;
401       synchronized (vt)
402     {
403       while (true)
404         {
405           vt.wait(ms, ns);
406           now = System.currentTimeMillis();
407           if (now >= end)
408         break;
409           ms = end - now;
410           ns = 0;
411         }
412     }
413     }
414 
415     /**
416      * Determine whether the current Thread has been interrupted, and clear
417      * the <i>interrupted status</i> in the process.
418      *
419      * @return whether the current Thread has been interrupted
420      */
421     static native boolean interrupted();
422 
423     /**
424      * Checks whether the current thread holds the monitor on a given object.
425      * This allows you to do <code>assert Thread.holdsLock(obj)</code>.
426      *
427      * @param obj the object to check
428      * @return true if the current thread is currently synchronized on obj
429      * @throws NullPointerException if obj is null
430      */
431     static boolean holdsLock(Object obj) 
432     {
433       /* Use obj.notify to check if the current thread holds
434        * the monitor of the object.
435        * If it doesn't, notify will throw an exception.
436        */
437       try 
438     {
439       obj.notify();
440       // okay, current thread holds lock
441       return true;
442     }
443       catch (IllegalMonitorStateException e)
444     {
445       // it doesn't hold the lock
446       return false;
447     }
448     }
View Code

http://docjar.com/docs/api/java/lang/package-index.htmlapi

  1. 利用對象,可將一個程序分割成相互獨立的區域。咱們一般也須要將一個程序轉換成多個獨立運行的子任務。象這樣的每一個子任務都叫做一個「線程」(Thread)。編寫程序時,可將每一個線程都想象成獨立運行,並且都有本身的專用CPU。一些基礎機制實際會爲咱們自動分割CPU的時間。
  2. 「進程 process」是指一種「自包容」 self-contained的運行程序,有本身的地址空間。「多任務」操做系統能同時運行多個進程(程序)——但實際是因爲CPU分時機制的做用,使每一個進程都能循環得到本身的CPU時間片。但因爲輪換速度很是快,使得全部程序好象是在「同時」運行同樣。「線程」是進程內部單一的一個順序控制流。所以,一個進程可能容納了多個同時執行的線程。
  3. 事實上,多線程最主要的一個用途就是構建一個「反應靈敏」的用戶界面 Graphical User Interface。Fast response on GUI.
  4. sleep()必須同一個Thread(線程)對象關聯到一塊兒,並且彷佛每一個應用程序都有部分線程同它關聯(事實上,Java自己就是創建在線程基礎上的,確定有一些線程會伴隨咱們寫的應用一塊兒運行)。因此不管咱們是否明確使用了線程,均可利用Thread.currentThread()產生由程序使用的當前線程,而後爲那個線程調用sleep()。注意,Thread.currentThread()是Thread類的一個靜態方法。
  5. 爲建立一個線程,最簡單的方法就是從Thread類繼承。這個類包含了建立和運行線程所需的一切東西。Thread最重要的方法是run()。但爲了使用run(),必須對其進行過載或者覆蓋,使其能充分按本身的吩咐行事。所以,run()屬於那些會與程序中的其餘線程「併發」或「同時」執行的代碼。
  6. run()方法幾乎確定含有某種形式的循環 loop (While)——它們會一直持續到線程再也不須要爲止。所以,咱們必須規定特定的條件,以便中斷並退出這個循環(或者在上述的例子中,簡單地從run()返回便可。run()一般採用一種無限循環infinite loop的形式。也就是說,經過阻止外部發出對線程的stop()或者destroy()調用,它會永遠運行下去(直到程序完成)。
  7. Thread包含了一個特殊的方法,叫做start(),它的做用是對線程進行特殊的初始化,而後調用run()。因此整個步驟包括:調用構建器來構建對象,而後用start()配置線程,再調用run()。若是不調用start()——若是適當的話 if proper,可在構建器那樣作——線程便永遠不會啓動。
  8. 亦可看出線程並非按它們建立時的順序運行的。事實上,CPU處理一個現有線程集的順序是不肯定的——除非咱們親自介入,並用Thread的setPriority()方法調整它們的優先級。priority
  9. 這個接口叫做Runnable (interface),其中包含了與Thread一致的基本方法。事實上,Thread也實現了Runnable,它只指出有一個run()方法。對合並後的程序/線程來講,它的用法不是十分明確。當咱們啓動程序時,會建立一個Runnable(可運行的)對象,但不會自行啓動線程。線程的啓動必須明確進行。
  10. Runnable接口最大的一個優勢是全部東西都從屬於相同的類。若需訪問什麼東西,只需簡單地訪問它便可,不須要涉及一個獨立的對象。但爲這種便利也是要付出代價的——只可爲那個特定的對象運行單獨一個線程(儘管可建立那種類型的多個對象,或者在不一樣的類裏建立其餘對象)。注意Runnable接口自己並非形成這一限制的罪魁禍首。它是因爲Runnable與咱們的主類合併形成的,由於每一個應用只能主類的一個對象。
  11. 「Daemon」線程的做用是在程序的運行期間於後臺提供一種「常規」服務,但它並不屬於程序的一個基本部分。所以,一旦全部非Daemon線程完成,程序也會停止運行。相反,倘若有任何非Daemon線程仍在運行(好比還有一個正在運行main()的線程),則程序的運行不會停止。經過調用isDaemon(),可調查一個線程是否是一個Daemon,並且能用setDaemon()打開或者關閉一個線程的Daemon狀態。若是是一個Daemon線程,那麼它建立的任何線程也會自動具有Daemon屬性。
  12. 可將單線程程序想象成一種孤立的實體,它能遍歷咱們的問題空間,並且一次只能作一件事情。因爲只有一個實體,因此永遠沒必要擔憂會有兩個實體同時試圖使用相同的資源,就象兩我的同時都想停到一個車位,同時都想經過一扇門,甚至同時發話。進入多線程環境後,它們則不再是孤立的。可能會有兩個甚至更多的線程試圖同時同一個有限的資源。必須對這種潛在資源衝突進行預防,不然就可能發生兩個線程同時訪問一個銀行賬號,打印到同一臺計算機,以及對同一個值進行調整等等。
  13. 爲防止出現這樣的衝突,只需在線程使用一個資源時爲其加鎖便可。訪問資源的第一個線程會其加上鎖之後,其餘線程便不能再使用那個資源,除非被解鎖。若是車子的前座是有限的資源,高喊「這是個人!」的孩子會主張把它鎖起來。
  14. 對一種特殊的資源——對象中的內存——Java提供了內建的機制來防止它們的衝突。因爲咱們一般將數據元素設爲從屬於private(私有)類,而後只經過方法訪問那些內存,因此只需將一個特定的方法設爲synchronized(同步的),即可有效地防止衝突。在任什麼時候刻,只可有一個線程調用特定對象的一個synchronized方法(儘管那個線程能夠調用多個對象的同步方法)。下面列出簡單的synchronized方法:
    synchronized void f() { /* ... */ } for one object of Class
  15. 每一個對象都包含了一把鎖(也叫做「監視器」),它自動成爲對象的一部分(沒必要爲此寫任何特殊的代碼)。調用任何synchronized方法時,對象就會被鎖定,不可再調用那個對象的其餘任何synchronized方法,除非第一個方法完成了本身的工做,並解除鎖定。
  16. 每一個類也有本身的一把鎖(做爲類的Class對象的一部分),因此synchronized static (for all object of Class)法可在一個類的範圍內被相互間鎖定起來,防止與static數據的接觸。注意若是想保護其餘某些資源不被多個線程同時訪問,能夠強制經過synchronized方訪問那些資源。
  17. 若是隻同步其中的一個方法,那麼另外一個就能夠自由忽視對象的鎖定,並可無礙地調用。因此必須記住一個重要的規則:對於訪問某個關鍵共享資源的全部方法,都必須把它們設爲synchronized,不然就不能正常地工做。
  18. If the function has the resource which is used in another synchronized function, it shall be defined as synchronized function.
  19. 因爲要爲一樣的數據編寫兩個方法,因此不管如何都不會給人留下效率很高的印象。看來彷佛更好的一種作法是將全部方法都設爲自動同步,並徹底消除synchronized關鍵字(固然,含有synchronized run()的例子顯示出這樣作是很不通的)。但它也揭示出獲取一把鎖並不是一種「廉價」方案——爲一次方法調用付出的代價(進入和退出方法,不執行方法主體)至少要累加到四倍,並且根據咱們的具體現方案,這一代價還有可能變得更高。因此假如已知一個方法不會形成衝突,最明智的作法即是撤消其中的synchronized關鍵字。
  20. 一個線程能夠有四種狀態:
    (1) 新(New):線程對象已經建立,但還沒有啓動,因此不可運行。
    (2) 可運行(Runnable):意味着一旦時間分片機制有空閒的CPU週期提供給一個線程,那個線程即可當即開始運行。所以,線程可能在、也可能不在運行當中,但一旦條件許可,沒有什麼能阻止它的運行——它既沒有「死」掉,也未被「堵塞」。
    (3) 死(Dead):從本身的run()方法中返回後,一個線程便已「死」掉。亦可調用stop()令其死掉,但會產生一個違例——屬於Error的一個子類(也就是說,咱們一般不捕獲它)。記住一個違例的「擲」出應當是一個特殊事件,而不是正常程序運行的一部分。因此不建議你使用stop()(在Java 1.2則是堅定反對)。另外還有一個destroy()方法(它永遠不會實現),應該儘量地避免調用它,由於它很是武斷,根本不會解除對象的鎖定。
    (4) 堵塞(Blocked):線程能夠運行,但有某種東西阻礙了它。若線程處於堵塞狀態,調度機制能夠簡單地跳過它,不給它分配任何CPU時間。除非線程再次進入「可運行」狀態,不然不會採起任何操做。
  21. 堵塞狀態是前述四種狀態中最有趣的,值得咱們做進一步的探討。線程被堵塞多是由下述五方面的緣由形成的:
    (1) 調用sleep(毫秒數),使線程進入「睡眠」狀態。在規定的時間內,這個線程是不會運行的。
    (2) 用suspend()暫停了線程的執行。除非線程收到resume()消息,不然不會返回「可運行」狀態。
    (3) 用wait()暫停了線程的執行。除非線程收到notify()或者notifyAll()消息,不然不會變成「可運行」(是的,這看起來同緣由2很是相象,但有一個明顯的區別是咱們立刻要揭示的)。
    (4) 線程正在等候一些IO(輸入輸出)操做完成。
    (5) 線程試圖調用另外一個對象的「同步」方法synchronized function,但那個對象處於鎖定狀態,暫時沒法使用。
  22. 這是因爲wait()在掛起內部調用的方法時,會解除對象的鎖定。
  23. 若一個數據流必須等候一些IO活動,便會自動進入「堵塞」狀態。在本例下面列出的部分中,有兩個類協同通用的Reader以及Writer對象工做(使用Java 1.1的流)。但在測試模型中,會設置一個管道化的數據流,使兩個線程相互間能安全地傳遞數據(這正是使用管道流的目的)。Sender將數據置入Writer,並「睡眠」隨機長短的時間。然而,Receiver自己並無包括sleep(),suspend()或者wait()方法。但在執行read()的時候,若是沒有數據存在,它會自動進入「堵塞」狀態。
  24. 因爲線程可能進入堵塞狀態,並且因爲對象可能擁有「同步」方法——除非同步鎖定被解除,不然線程不能訪問那個對象——因此一個線程徹底可能等候另外一個對象,而另外一個對象又在等候下一個對象,以此類推。這個「等候」鏈最可怕的情形就是進入封閉狀態——最後那個對象等候的是第一個對象!此時,全部線程都會陷入無休止的相互等待狀態,你們都動彈不得。咱們將這種狀況稱爲「死鎖」。Dead lock
  25. 爲減小出現死鎖的可能,Java 1.2做出的一項貢獻是「反對」使用Thread的stop(),suspend(),resume()以及destroy()方法。之因此反對使用stop(),是由於它不安全。它會解除由線程獲取的全部鎖定,並且若是對象處於一種不連貫狀態(「被破壞」),那麼其餘線程能在那種狀態下檢查和修改它們。結果便形成了一種微妙的局面,咱們很難檢查出真正的問題所在。因此應儘可能避免使用stop(),應該採用Blocking.java那樣的方法,用一個標誌告訴線程何時經過退出本身的run()方法來停止本身的執行。
  26. 線程的優先級(Priority)告訴調試程序該線程的重要程度有多大。若是有大量線程都被堵塞,都在等候運行,調試程序會首先運行具備最高優先級的那個線程。然而,這並不表示優先級較低的線程不會運行(換言之,不會由於存在優先級而致使死鎖)。若線程的優先級較低,只不過表示它被准許運行的機會小一些而已。可用getPriority()方法讀取一個線程的優先級,並用setPriority()改變它。
  27. 「線程組中的線程能夠修改組內的其餘線程,包括那些位於分層結構最深處的。一個線程不能修改位於本身所在組或者下屬組以外的任何線程」
  28. 全部線程都隸屬於一個線程組。那能夠是一個默認線程組,亦但是一個建立線程時明確指定的組。在建立之初,線程被限制到一個組裏,並且不能改變到一個不一樣的組。每一個應用都至少有一個線程從屬於系統線程組。若建立多個線程而不指定一個組,它們就會自動歸屬於系統線程組。線程組也必須從屬於其餘線程組。必須在構建器裏指定新線程組從屬於哪一個線程組。若在建立一個線程組的時候沒有指定它的歸屬,則一樣會自動成爲系統線程組的一名屬下。所以,一個應用程序中的全部線程組最終都會將系統線程組做爲本身的「父」。
  29. 固然,若是必須從一個類繼承,並且想使類具備線程處理能力,則Runnable是一種正確的方案。
  30. 若是在一個多線程的程序中遇到了性能上的問題,那麼如今有許多因素須要檢查:
    (1) 對sleep,yield()以及/或者wait()的調用足夠多嗎?
    (2) sleep()的調用時間足夠長嗎?
    (3) 運行的線程數是否是太多?
    (4) 試過不一樣的平臺和JVM嗎?
    象這樣的一些問題是形成多線程應用程序的編製成爲一種「技術活」的緣由之一。
  31. 什麼時候使用多線程技術,以及什麼時候避免用它,這是咱們須要掌握的重要課題。骼它的主要目的是對大量任務進行有序的管理。經過多個任務的混合使用,能夠更有效地利用計算機資源,或者對用戶來講顯得更方便。資源均衡的經典問題是在IO等候期間如何利用CPU。至於用戶方面的方便性,最經典的問題就是如何在一個長時間的下載過程當中監視並靈敏地反應一個「中止」(stop)按鈕的按下。
    多線程的主要缺點包括:
    (1) 等候使用共享資源時形成程序的運行速度變慢。
    (2) 對線程進行管理要求的額外CPU開銷。
    (3) 複雜程度無心義的加大,好比用獨立的線程來更新數組內每一個元素的愚蠢主意。
    (4) 漫長的等待、浪費精力的資源競爭以及死鎖等多線程症狀。
  32. 線程另外一個優勢是它們用「輕度」執行切換(100條指令的順序)取代了「重度」進程場景切換(1000條指令)。因爲一個進程內的全部線程共享相同的內存空間,因此「輕度」場景切換隻改變程序的執行和本地變量。而在「重度」場景切換時,一個進程的改變要求必須完整地交換內存空間。
  33. 多個線程可能共享同一個資源(好比一個對象裏的內存),這是運用線程時面臨的最大的一個麻煩。必須保證多個線程不會同時試圖讀取和修改那個資源。這要求技巧性地運用synchronized(同步)關鍵字。它是一個有用的工具,但必須真正掌握它,由於倘若操做不當,極易出現死鎖。
  34. 因爲採用了線程「調度」機制,因此經過在run()的主循環中插入對sleep()的調用,通常均可以使本身的程序運行得更快一些。這使它對編程技巧的要求很是高,特別是在更長的延遲彷佛反而能提升性能的時候。固然,之因此會出現這種狀況,是因爲在正在運行的線程準備進入「休眠」狀態以前,較短的延遲可能形成「sleep()結束」調度機制的中斷。這便強迫調度機制將其停止,並於稍後從新啓動,以便它能作完本身的事情,再進入休眠狀態。必須多想想,才能意識到事情真正的麻煩程度.
相關文章
相關標籤/搜索