Java 8之Thread類源碼

1、start方法html

一個線程一旦已經被start了就不能再次執行start方法。被start過的線程,線程狀態已經不是0了,線程狀態總共有5種狀態java

//線程啓動執行,jvm調用線程的run方法
	//產生的結果是由兩個線程同時運行,一個是當前線程調用start方法的線程,一個是
	//執行run方法的線程。
    /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    public synchronized void start() {
		//這個方法不是給main方法線程或者VM建立的系統組線程調用的。任何將來可能被添加到該
		//方法的功能,未來也許會同時加到虛擬機。狀態0表示狀態 NEW。一旦線程被啓動以後該值
		//將會被改變,同一線程被啓動屢次就會出現異常,不論是執行中仍是執行完成該線程都不能
		//再次被start。若是一個線程正在執行中進行start,該值爲2表示是Runnable,若是該值爲5
		//則表示爲Terminated。
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

		//通知組,該線程將被啓動並將線程添加到組的線程列表裏,同時組未啓動計數將減一
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

		//是否啓動
        boolean started = false;
        try {
		//調用線程本地方法
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

2、join方法bootstrap

join方法本質上調用的是Object的wait方法,線程結束時會調用Object的喚醒方法。數組

//等待線程執行完成最多指定毫秒數時間。0,表示永不超時。該實現用的是循環等待
	//鑑於,線程終止時notifyAll方法將被調用,因此不建議應用在Thread實例對象使用
	//wait,notify或者notifyAll方法。
    /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                //調用Object的wait方法
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

3、interrupt方法安全

線程中斷方法,當代碼調用sleep,join,wait的方法時,咱們都會被要求顯示捕獲InterruptedException,這就是當線程被外部中斷時,當執行到這個地方的時候會被中斷。併發

//除非中斷本身,checkAccess都將被調用
    /**
     * Interrupts this thread.
     *
     * <p> Unless the current thread is interrupting itself, which is
     * always permitted, the {@link #checkAccess() checkAccess} method
     * of this thread is invoked, which may cause a {@link
     * SecurityException} to be thrown.
     *
	 //若是一個線程阻塞在wat方法,或者線程的join方法,再或者sleep方法上,
	 //線程的中斷狀態被清空設置爲false,而且被interrupt的線程將收到一箇中斷異常。
     * <p> If this thread is blocked in an invocation of the {@link
     * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
     * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
     * class, or of the {@link #join()}, {@link #join(long)}, {@link
     * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
     * methods of this class, then its interrupt status will be cleared and it
     * will receive an {@link InterruptedException}.
     *
	 //若是線程阻塞在IO操做,channel將被關閉,而且線程的中斷狀態會被設置爲true,
	 //而且被interrupt的線程將收到一個ClosedByInterruptException異常。
     * <p> If this thread is blocked in an I/O operation upon an {@link
     * java.nio.channels.InterruptibleChannel InterruptibleChannel}
     * then the channel will be closed, the thread's interrupt
     * status will be set, and the thread will receive a {@link
     * java.nio.channels.ClosedByInterruptException}.
     *
	 //若是線程阻塞在selector方法,中斷線程的中斷狀態將設置爲true,而且從select操做當即返回,
	 //只有selector的wakeup方法被調用可能返回一個非0值。
     * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
     * then the thread's interrupt status will be set and it will return
     * immediately from the selection operation, possibly with a non-zero
     * value, just as if the selector's {@link
     * java.nio.channels.Selector#wakeup wakeup} method were invoked.
     *//若是不是上面說的幾種狀況,線程的中斷狀態將被設置。
     * <p> If none of the previous conditions hold then this thread's interrupt
     * status will be set. </p>
     *
     * <p> Interrupting a thread that is not alive need not have any effect.
     *
     * @throws  SecurityException
     *          if the current thread cannot modify this thread
     *
     * @revised 6.0
     * @spec JSR-51
     */
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }

4、setPriorityapp

設置線程優先級,優先得到執行權,默認優先級是5,最小優先級是1,最大優先級是10less

//改變線程優先級。
	//首先執行checkAccess查看權限。最小被設置爲指定的值,最大爲線程組的值。
	//根據此能夠發現一個線程設置優先級必須歸屬於某個線程組。
    /**
     * Changes the priority of this thread.
     * <p>
     * First the <code>checkAccess</code> method of this thread is called
     * with no arguments. This may result in throwing a
     * <code>SecurityException</code>.
     * <p>
     * Otherwise, the priority of this thread is set to the smaller of
     * the specified <code>newPriority</code> and the maximum permitted
     * priority of the thread's thread group.
     *
     * @param newPriority priority to set this thread to
     * @exception  IllegalArgumentException  If the priority is not in the
     *               range <code>MIN_PRIORITY</code> to
     *               <code>MAX_PRIORITY</code>.
     * @exception  SecurityException  if the current thread cannot modify
     *               this thread.
     * @see        #getPriority
     * @see        #checkAccess()
     * @see        #getThreadGroup()
     * @see        #MAX_PRIORITY
     * @see        #MIN_PRIORITY
     * @see        ThreadGroup#getMaxPriority()
     */
    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

5、yield方法jvm

讓出處理器使用ide

//示意線程調度器,當前線程但願讓出正在使用的處理器。調度器能夠忽略此請求。
	//讓出是探索式的嘗試,目的是提升線程間相對運行進展不致於某個線程過分使用CPU。
	//yield的使用應該結合詳細的文檔分析和不斷基準測試來保證它真正實現指望的效果。
	//不多有合適場合使用此方法。對以測試爲目的的debug也許是有用的,好比由於競爭條件
	//復現一線bug。設計併發控制結構也可能頗有用,好比concurrent.locks包併發控制結構中
	//就有一些使用yield方法。
    /**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     *
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     *
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     */
    public static native void yield();

6、sleep方法

//讓當前執行的線程睡眠指定的時間。當前線程不會失去任何監視器的擁有權。
    /**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public static native void sleep(long millis) throws InterruptedException;

7、init線程

當new Thread一個線程時將執行init方法,Thread構造器會調用到這個方法。

/**
     * Initializes a Thread.
     *
     * @param g the Thread group
     * @param target the object whose run() method gets called
     * @param name the name of the new Thread
     * @param stackSize the desired stack size for the new thread, or
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or
     *            AccessController.getContext() if null
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
		//線程必須設置名稱,不然拋出空指針異常
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name.toCharArray();

		//父線程
        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        //若是線程組爲null
        if (g == null) {
            /* Determine if it's an applet or not */
            //若是有安全管理器,從安全管理器得到線程組
            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }
            //若是安全管理器也不知道線程組,那麼從父線程獲取線程組,也就是線程必須歸屬於某個線程組
            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        g.checkAccess();

        /*
         * Do we have the required permissions?
         //校驗是否有安全校驗權利,若是重寫了getContextClassLoader和setContextClassLoader
         */
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        //線程組添加未啓動線程
        g.addUnstarted();

        this.group = g;
		//父線程的守護線程屬性
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

8、線程狀態

public enum State {
		//線程還沒有啓動時處於此狀態
        /**
         * Thread state for a thread which has not yet started.
         */
        NEW,

		//容許中的線程狀態,runnable表示線程在jvm中運行可是可能在等待操做系統的其餘資源,好比處理器
        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
        RUNNABLE,

		//線程阻塞在等待監視器的鎖,線程處於blocked狀態是指它在等待監視器鎖來進如同步的方法或者塊或者是在調用了wait方法後從新進入一個同步
		//方法或者同步塊。
        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,

		//處於等待狀態的線程,在調用未設置超時的object的wait()方法,或者Thread的join(),或者LockSupport.park()方法後
		//線程處於等待狀態是指在等待另一個線程執行特殊操做。例如線程調用object的wait以後等待另一個線程執行notify
		//或者notifyAll方法。線程調用Thread.join是在等待指定的線程終止以後執行操做。
        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

		//指定時間的等待,線程處於此狀態是因爲調用以下方法指定正數等待時間:
		//Thread.sleep,Object.wait,Thread.join,LockSupport.parkNanos,LockSupport.parkUntil
        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
        TIMED_WAITING,

		//線程結束狀態,表示線程已經完成執行。
        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
        TERMINATED;
    }

9、被棄用的方法

stop,suspend,resume都再也不使用

//掛起當前線程。checkAccess校驗權限。若是線程存活時被掛起,將不會繼續執行,
	//直到調用resume方法。
	//由於容易引發死鎖,該方法已經被棄用。好比,目標線程持有一個重要資源的鎖時被
	//掛起,直到目標線程被恢復將沒有線程能夠訪問這個資源。若是恢復目標線程的線程嘗試在調用
	//resume方法以前優先鎖住資源的監視器將產生死鎖。同stop,resume同樣都被棄用。
    /**
     * Suspends this thread.
     * <p>
     * First, the <code>checkAccess</code> method of this thread is called
     * with no arguments. This may result in throwing a
     * <code>SecurityException </code>(in the current thread).
     * <p>
     * If the thread is alive, it is suspended and makes no further
     * progress unless and until it is resumed.
     *
     * @exception  SecurityException  if the current thread cannot modify
     *               this thread.
     * @see #checkAccess
     * @deprecated   This method has been deprecated, as it is
     *   inherently deadlock-prone.  If the target thread holds a lock on the
     *   monitor protecting a critical system resource when it is suspended, no
     *   thread can access this resource until the target thread is resumed. If
     *   the thread that would resume the target thread attempts to lock this
     *   monitor prior to calling <code>resume</code>, deadlock results.  Such
     *   deadlocks typically manifest themselves as "frozen" processes.
     *   For more information, see
     *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
    @Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }

10、enumerate方法

//將本線程所屬線程組及其子組中存活的線程拷貝到指定的線程數組中。該線程簡單的調用
	//線程組的enumerate方法。應用也許會使用activeCount()方法來獲取數組的大體大小,然而,若是
	//數組過小不可以保存全部線程,多出的線程將被忽略。若是獲取當前線程所屬線程組和子組的存活線程
	//是個重要的事兒,調用者應該確認返回的值應該嚴格小於數組的長度。
    /**
     * Copies into the specified array every active thread in the current
     * thread's thread group and its subgroups. This method simply
     * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
     * method of the current thread's thread group.
     *
     * <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 the current thread's thread group and its subgroups, the
     * invoker should verify that the returned int value is strictly less
     * than the length of {@code tarray}.
     *
     * <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  tarray
     *         an array into which to put the list of threads
     *
     * @return  the number of threads put into the array
     *
     * @throws  SecurityException
     *          if {@link java.lang.ThreadGroup#checkAccess} determines that
     *          the current thread cannot access its thread group
     */
    public static int enumerate(Thread tarray[]) {
        return currentThread().getThreadGroup().enumerate(tarray);
    }

11、上下文類加載器

//返回線程的上下文類加載器。上下文類加載器是由線程建立者提供,當線程須要加載類
	//或者資源時使用。若是沒有設置上下文類加載器,缺省的類加載器上下文是父線程。原始線程
	//的上下文類加載器一般是告訴類加載器加載應用。若是存在安全管理器,調用者的類加載器不爲null
	//這個方法將調用安全管理器的checkPermission(),將會校驗是否容許返回上下文類加載器。
    /**
     * Returns the context ClassLoader for this Thread. The context
     * ClassLoader is provided by the creator of the thread for use
     * by code running in this thread when loading classes and resources.
     * If not {@linkplain #setContextClassLoader set}, the default is the
     * ClassLoader context of the parent Thread. The context ClassLoader of the
     * primordial thread is typically set to the class loader used to load the
     * application.
     *
     * <p>If a security manager is present, and the invoker's class loader is not
     * {@code null} and is not the same as or an ancestor of the context class
     * loader, then this method invokes the security manager's {@link
     * SecurityManager#checkPermission(java.security.Permission) checkPermission}
     * method with a {@link RuntimePermission RuntimePermission}{@code
     * ("getClassLoader")} permission to verify that retrieval of the context
     * class loader is permitted.
     *
     * @return  the context ClassLoader for this Thread, or {@code null}
     *          indicating the system class loader (or, failing that, the
     *          bootstrap class loader)
     *
     * @throws  SecurityException
     *          if the current thread cannot get the context ClassLoader
     *
     * @since 1.2
     */
    @CallerSensitive
    public ClassLoader getContextClassLoader() {
        if (contextClassLoader == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                                   Reflection.getCallerClass());
        }
        return contextClassLoader;
    }

	//設置線程的上下文類加載器。上下文類加載器在線程建立時設置,並容許線程建立者提供合適的類加載器來對應到代碼,
	//經過getContextClassLoader()來獲取類加載器來加載類和資源以處理線程中運行的代碼。
    /**
     * Sets the context ClassLoader for this Thread. The context
     * ClassLoader can be set when a thread is created, and allows
     * the creator of the thread to provide the appropriate class loader,
     * through {@code getContextClassLoader}, to code running in the thread
     * when loading classes and resources.
     *
     * <p>If a security manager is present, its {@link
     * SecurityManager#checkPermission(java.security.Permission) checkPermission}
     * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
     * ("setContextClassLoader")} permission to see if setting the context
     * ClassLoader is permitted.
     *
     * @param  cl
     *         the context ClassLoader for this Thread, or null  indicating the
     *         system class loader (or, failing that, the bootstrap class loader)
     *
     * @throws  SecurityException
     *          if the current thread cannot set the context ClassLoader
     *
     * @since 1.2
     */
    public void setContextClassLoader(ClassLoader cl) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
        }
        contextClassLoader = cl;
    }
相關文章
相關標籤/搜索