1094 lines · 38.4 KB · Java
RawDownload
/* * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.lang; import java.io.PrintStream;import java.util.Arrays;import sun.misc.VM; /** * A thread group represents a set of threads. In addition, a thread * group can also include other thread groups. The thread groups form * a tree in which every thread group except the initial thread group * has a parent. * <p> * A thread is allowed to access information about its own thread * group, but not to access information about its thread group's * parent thread group or any other thread groups. * * @author  unascribed * @since   JDK1.0 *//* The locking strategy for this code is to try to lock only one level of the * tree wherever possible, but otherwise to lock from the bottom up. * That is, from child thread groups to parents. * This has the advantage of limiting the number of locks that need to be held * and in particular avoids having to grab the lock for the root thread group, * (or a global lock) which would be a source of contention on a * multi-processor system with many thread groups. * This policy often leads to taking a snapshot of the state of a thread group * and working off of that snapshot, rather than holding the thread group locked * while we work on the children. */publicclass ThreadGroup implements Thread.UncaughtExceptionHandler {    private final ThreadGroup parent;    String name;    int maxPriority;    boolean destroyed;    boolean daemon;    boolean vmAllowSuspension;     int nUnstartedThreads = 0;    int nthreads;    Thread threads[];     int ngroups;    ThreadGroup groups[];     /**     * Creates an empty Thread group that is not in any Thread group.     * This method is used to create the system Thread group.     */    private ThreadGroup() {     // called from C code        this.name = "system";        this.maxPriority = Thread.MAX_PRIORITY;        this.parent = null;    }     /**     * Constructs a new thread group. The parent of this new group is     * the thread group of the currently running thread.     * <p>     * The <code>checkAccess</code> method of the parent thread group is     * called with no arguments; this may result in a security exception.     *     * @param   name   the name of the new thread group.     * @exception  SecurityException  if the current thread cannot create a     *               thread in the specified thread group.     * @see     java.lang.ThreadGroup#checkAccess()     * @since   JDK1.0     */    public ThreadGroup(String name) {        this(Thread.currentThread().getThreadGroup(), name);    }     /**     * Creates a new thread group. The parent of this new group is the     * specified thread group.     * <p>     * The <code>checkAccess</code> method of the parent thread group is     * called with no arguments; this may result in a security exception.     *     * @param     parent   the parent thread group.     * @param     name     the name of the new thread group.     * @exception  NullPointerException  if the thread group argument is     *               <code>null</code>.     * @exception  SecurityException  if the current thread cannot create a     *               thread in the specified thread group.     * @see     java.lang.SecurityException     * @see     java.lang.ThreadGroup#checkAccess()     * @since   JDK1.0     */    public ThreadGroup(ThreadGroup parent, String name) {        this(checkParentAccess(parent), parent, name);    }     private ThreadGroup(Void unused, ThreadGroup parent, String name) {        this.name = name;        this.maxPriority = parent.maxPriority;        this.daemon = parent.daemon;        this.vmAllowSuspension = parent.vmAllowSuspension;        this.parent = parent;        parent.add(this);    }     /*     * @throws  NullPointerException  if the parent argument is {@code null}     * @throws  SecurityException     if the current thread cannot create a     *                                thread in the specified thread group.     */    private static Void checkParentAccess(ThreadGroup parent) {        parent.checkAccess();        return null;    }     /**     * Returns the name of this thread group.     *     * @return  the name of this thread group.     * @since   JDK1.0     */    public final String getName() {        return name;    }     /**     * Returns the parent of this thread group.     * <p>     * First, if the parent is not <code>null</code>, the     * <code>checkAccess</code> method of the parent thread group is     * called with no arguments; this may result in a security exception.     *     * @return  the parent of this thread group. The top-level thread group     *          is the only thread group whose parent is <code>null</code>.     * @exception  SecurityException  if the current thread cannot modify     *               this thread group.     * @see        java.lang.ThreadGroup#checkAccess()     * @see        java.lang.SecurityException     * @see        java.lang.RuntimePermission     * @since   JDK1.0     */    public final ThreadGroup getParent() {        if (parent != null)            parent.checkAccess();        return parent;    }     /**     * Returns the maximum priority of this thread group. Threads that are     * part of this group cannot have a higher priority than the maximum     * priority.     *     * @return  the maximum priority that a thread in this thread group     *          can have.     * @see     #setMaxPriority     * @since   JDK1.0     */    public final int getMaxPriority() {        return maxPriority;    }     /**     * Tests if this thread group is a daemon thread group. A     * daemon thread group is automatically destroyed when its last     * thread is stopped or its last thread group is destroyed.     *     * @return  <code>true</code> if this thread group is a daemon thread group;     *          <code>false</code> otherwise.     * @since   JDK1.0     */    public final boolean isDaemon() {        return daemon;    }     /**     * Tests if this thread group has been destroyed.     *     * @return  true if this object is destroyed     * @since   JDK1.1     */    public synchronized boolean isDestroyed() {        return destroyed;    }     /**     * Changes the daemon status of this thread group.     * <p>     * First, the <code>checkAccess</code> method of this thread group is     * called with no arguments; this may result in a security exception.     * <p>     * A daemon thread group is automatically destroyed when its last     * thread is stopped or its last thread group is destroyed.     *     * @param      daemon   if <code>true</code>, marks this thread group as     *                      a daemon thread group; otherwise, marks this     *                      thread group as normal.     * @exception  SecurityException  if the current thread cannot modify     *               this thread group.     * @see        java.lang.SecurityException     * @see        java.lang.ThreadGroup#checkAccess()     * @since      JDK1.0     */    public final void setDaemon(boolean daemon) {        checkAccess();        this.daemon = daemon;    }     /**     * Sets the maximum priority of the group. Threads in the thread     * group that already have a higher priority are not affected.     * <p>     * First, the <code>checkAccess</code> method of this thread group is     * called with no arguments; this may result in a security exception.     * <p>     * If the <code>pri</code> argument is less than     * {@link Thread#MIN_PRIORITY} or greater than     * {@link Thread#MAX_PRIORITY}, the maximum priority of the group     * remains unchanged.     * <p>     * Otherwise, the priority of this ThreadGroup object is set to the     * smaller of the specified <code>pri</code> and the maximum permitted     * priority of the parent of this thread group. (If this thread group     * is the system thread group, which has no parent, then its maximum     * priority is simply set to <code>pri</code>.) Then this method is     * called recursively, with <code>pri</code> as its argument, for     * every thread group that belongs to this thread group.     *     * @param      pri   the new priority of the thread group.     * @exception  SecurityException  if the current thread cannot modify     *               this thread group.     * @see        #getMaxPriority     * @see        java.lang.SecurityException     * @see        java.lang.ThreadGroup#checkAccess()     * @since      JDK1.0     */    public final void setMaxPriority(int pri) {        int ngroupsSnapshot;        ThreadGroup[] groupsSnapshot;        synchronized (this) {            checkAccess();            if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {                return;            }            maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;            ngroupsSnapshot = ngroups;            if (groups != null) {                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);            } else {                groupsSnapshot = null;            }        }        for (int i = 0 ; i < ngroupsSnapshot ; i++) {            groupsSnapshot[i].setMaxPriority(pri);        }    }     /**     * Tests if this thread group is either the thread group     * argument or one of its ancestor thread groups.     *     * @param   g   a thread group.     * @return  <code>true</code> if this thread group is the thread group     *          argument or one of its ancestor thread groups;     *          <code>false</code> otherwise.     * @since   JDK1.0     */    public final boolean parentOf(ThreadGroup g) {        for (; g != null ; g = g.parent) {            if (g == this) {                return true;            }        }        return false;    }     /**     * Determines if the currently running thread has permission to     * modify this thread group.     * <p>     * If there is a security manager, its <code>checkAccess</code> method     * is called with this thread group as its argument. This may result     * in throwing a <code>SecurityException</code>.     *     * @exception  SecurityException  if the current thread is not allowed to     *               access this thread group.     * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)     * @since      JDK1.0     */    public final void checkAccess() {        SecurityManager security = System.getSecurityManager();        if (security != null) {            security.checkAccess(this);        }    }     /**     * Returns an estimate of the number of active threads in this thread     * group and its subgroups. Recursively iterates over all subgroups in     * this thread group.     *     * <p> The value returned is only an estimate because the number of     * threads may change dynamically while this method traverses internal     * data structures, and might be affected by the presence of certain     * system threads. This method is intended primarily for debugging     * and monitoring purposes.     *     * @return  an estimate of the number of active threads in this thread     *          group and in any other thread group that has this thread     *          group as an ancestor     *     * @since   JDK1.0     */    public int activeCount() {        int result;        // Snapshot sub-group data so we don't hold this lock        // while our children are computing.        int ngroupsSnapshot;        ThreadGroup[] groupsSnapshot;        synchronized (this) {            if (destroyed) {                return 0;            }            result = nthreads;            ngroupsSnapshot = ngroups;            if (groups != null) {                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);            } else {                groupsSnapshot = null;            }        }        for (int i = 0 ; i < ngroupsSnapshot ; i++) {            result += groupsSnapshot[i].activeCount();        }        return result;    }     /**     * Copies into the specified array every active thread in this     * thread group and its subgroups.     *     * <p> An invocation of this method behaves in exactly the same     * way as the invocation     *     * <blockquote>     * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}     * </blockquote>     *     * @param  list     *         an array into which to put the list of threads     *     * @return  the number of threads put into the array     *     * @throws  SecurityException     *          if {@linkplain #checkAccess checkAccess} determines that     *          the current thread cannot access this thread group     *     * @since   JDK1.0     */    public int enumerate(Thread list[]) {        checkAccess();        return enumerate(list, 0, true);    }     /**     * Copies into the specified array every active thread in this     * thread group. If {@code recurse} is {@code true},     * this method recursively enumerates all subgroups of this     * thread group and references to every active thread in these     * subgroups are also included. If the array is too short to     * hold all the threads, the extra threads are silently ignored.     *     * <p> An application might use the {@linkplain #activeCount activeCount}     * method to get an estimate of how big the array should be, however     * <i>if the array is too short to hold all the threads, the extra threads     * are silently ignored.</i>  If it is critical to obtain every active     * thread in this thread group, the caller should verify that the returned     * int value is strictly less than the length of {@code list}.     *     * <p> Due to the inherent race condition in this method, it is recommended     * that the method only be used for debugging and monitoring purposes.     *     * @param  list     *         an array into which to put the list of threads     *     * @param  recurse     *         if {@code true}, recursively enumerate all subgroups of this     *         thread group     *     * @return  the number of threads put into the array     *     * @throws  SecurityException     *          if {@linkplain #checkAccess checkAccess} determines that     *          the current thread cannot access this thread group     *     * @since   JDK1.0     */    public int enumerate(Thread list[], boolean recurse) {        checkAccess();        return enumerate(list, 0, recurse);    }     private int enumerate(Thread list[], int n, boolean recurse) {        int ngroupsSnapshot = 0;        ThreadGroup[] groupsSnapshot = null;        synchronized (this) {            if (destroyed) {                return 0;            }            int nt = nthreads;            if (nt > list.length - n) {                nt = list.length - n;            }            for (int i = 0; i < nt; i++) {                if (threads[i].isAlive()) {                    list[n++] = threads[i];                }            }            if (recurse) {                ngroupsSnapshot = ngroups;                if (groups != null) {                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);                } else {                    groupsSnapshot = null;                }            }        }        if (recurse) {            for (int i = 0 ; i < ngroupsSnapshot ; i++) {                n = groupsSnapshot[i].enumerate(list, n, true);            }        }        return n;    }     /**     * Returns an estimate of the number of active groups in this     * thread group and its subgroups. Recursively iterates over     * all subgroups in this thread group.     *     * <p> The value returned is only an estimate because the number of     * thread groups may change dynamically while this method traverses     * internal data structures. This method is intended primarily for     * debugging and monitoring purposes.     *     * @return  the number of active thread groups with this thread group as     *          an ancestor     *     * @since   JDK1.0     */    public int activeGroupCount() {        int ngroupsSnapshot;        ThreadGroup[] groupsSnapshot;        synchronized (this) {            if (destroyed) {                return 0;            }            ngroupsSnapshot = ngroups;            if (groups != null) {                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);            } else {                groupsSnapshot = null;            }        }        int n = ngroupsSnapshot;        for (int i = 0 ; i < ngroupsSnapshot ; i++) {            n += groupsSnapshot[i].activeGroupCount();        }        return n;    }     /**     * Copies into the specified array references to every active     * subgroup in this thread group and its subgroups.     *     * <p> An invocation of this method behaves in exactly the same     * way as the invocation     *

Lines 1–500 of 1094.