zoukankan      html  css  js  c++  java
  • Programming for thread in Java

    Programming for thread in Java

    Override Annotation

     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 Interface

    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 Class

       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 Local

      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 Group

      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.html

    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()结束”调度机制的中断。这便强迫调度机制将其中止,并于稍后重新启动,以便它能做完自己的事情,再进入休眠状态。必须多想一想,才能意识到事情真正的麻烦程度.
  • 相关阅读:
    函数即变量
    装饰器模型
    团队配合指令
    三元指令
    虚实之门
    for的逻辑
    我写的第4个程序(日志最近行读取函数)
    还在用WebBrowser吗?你out了!
    关于打印机共享的注意事项——又被叫去修电脑了
    MVVM转换器Int2StringConverter基础类
  • 原文地址:https://www.cnblogs.com/iiiDragon/p/3272526.html
Copyright © 2011-2022 走看看