Thread

Thread閱讀筆記

問題

一、簡介

它是Java.lang包的一個類,調用系統內核來執行線程

二、繼承關係圖

在這裏插入圖片描述

三、源碼分析

內部類

  • 枚舉State類
public enum State {
    /**
     * 新建狀態:線程剛創建,還未執行start方法
     */
    NEW,

    /**
     * 可運行狀態:已經就緒可運行的狀態,處於此狀態的線程是正在JVM中運行的,
     * 				但可能再等待操作系統級別的資源,例如CPU時間片
     */
    RUNNABLE,

    /**
     * 阻塞狀態:阻塞等待監視器鎖,處於此狀態的線程正在阻塞等待監視器鎖,
     *			以進入一個同步塊/方法,或者再執行完wait()方法後重入同步塊/方法
     */
    BLOCKED,

    /**
     * 等待狀態:執行完Object.wait無超時參數操作,
     *			或者 Thread.join無超時參數操作
     *			或者 LockSupport.park 操作後,線程進入等待狀態
     * 一般在等待狀態的線程在等待其它線程執行特殊操作,例如:、		
     *	等待其它線程操作Object.notify() 喚醒 或 Object.notifyAll() 喚醒所有
     */
    WAITING,

    /**
     * 等待狀態:Thread.sleep、Object.await待超時時間、Thread.join帶超時時間
     * 		LockSupport.parkNanos、LockSupport.parkUntil這些 操作會使線程進入顯示等待
     */
    TIMED_WAITING,

    /**
     * 終止狀態(線程執行完畢)
     */
    TERMINATED;
}

屬性

// 線程名稱
private volatile String name; 
// 線程優先級
private int            priority;
private Thread         threadQ;
private long           eetop;
// 是否單步執行這個線程
private boolean     single_step;
// 是否爲守護線程
private boolean     daemon = false;
// JVM狀態值
private boolean     stillborn = false;
// 線程任務
private Runnable target;
// 線程組
private ThreadGroup group;
// 此線程的上下文類裝入器
private ClassLoader contextClassLoader;
// 它封裝的上下文做出系統資源訪問決策
private AccessControlContext inheritedAccessControlContext;

// 自動編號,就是當沒有設置線程名稱的時候,我們看到的thread-0、thread-1
private static int threadInitNumber;
// 線程堆棧空間大小,默認0,
private long stackSize;
// JVM私有狀態,在本機線程終止後仍然存在。
private long nativeParkEventPointer;
// 線程ID
private long tid;
// 用於生成線程ID
private static long threadSeqNumber;
// 線程初始狀態,表示線程尚未啓動
private volatile int threadStatus = 0;
volatile Object parkBlocker;
private volatile Interruptible blocker;
// 用於synchronized關鍵字的實例鎖
private final Object blockerLock = new Object();
// 最小優先級
public final static int MIN_PRIORITY = 1;
// 默認優先級
public final static int NORM_PRIORITY = 5;
// 最大優先級
public final static int MAX_PRIORITY = 10;

/** 線程自身的副本變量值 */
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

構造

/**
 *	總共8個公共構造和一個默認訪問權限的構造
 */
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

Thread(Runnable target, AccessControlContext acc) {
    init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}
public Thread(ThreadGroup group, Runnable target) {
    init(group, target, "Thread-" + nextThreadNum(), 0);
}
public Thread(String name) {
    init(null, null, name, 0);
}
public Thread(ThreadGroup group, String name) {
    init(group, null, name, 0);
}
public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name) {
    init(group, target, name, 0);
}
public Thread(ThreadGroup group, Runnable target, String name,
              long stackSize) {
    init(group, target, name, stackSize);
}

/**
 * 構造方法使用到的nextThreadNum函數-獲得全局自動編號
 */
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
    return threadInitNumber++;
}
/**
 * 構造方法使用到的 init 函數-初始化線程
 */
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize) {
    init(g, target, name, stackSize, null, true);
}
/**
 * 構造方法使用到的 init 函數-初始化線程,並封裝的上下文做出系統資源訪問策略
 */
private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
    if (name == null) {
        // 如果名稱爲null 拋出異常
        throw new NullPointerException("name cannot be null");
    }
	// 名稱賦值
    this.name = name;

    // 獲得當前線程(當前正在運行的線程)
    Thread parent = currentThread();
    // 安全管理器
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
        /* Determine if it's an applet or not */

        /* If there is a security manager, ask the security manager
               what to do. */
        // 如果安全管理器不爲null,則當前線程組就是優先用管理器指定的線程組
        if (security != null) {
            g = security.getThreadGroup();
        }

        /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
        // 如果線程組還是爲null 則使用父線程的線程組
        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?
         */
    if (security != null) {
        // 如果安全管理器不爲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 (inheritThreadLocals && 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 */
    // 設置線程Id
    tid = nextThreadID();
}

主要方法

1、start()-啓動方法
public synchronized void start() {
    /**
         * 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 {
        // 調用native方法
        start0();
        // 啓動成功,設置爲true
        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、run()-運行方法
@Override
public void run() {
    if (target != null) {
        // 直接調用線程任務
        target.run();
    }
}
3、exit()-退出方法-私有
private void exit() {
    if (group != null) {
        // 從線程組中移除自身,並notifyAll()
        group.threadTerminated(this);
        // 幫助gc
        group = null;
    }
    // 幫忙 GC
    /* Aggressively null out all reference fields: see bug 4006245 */
    target = null;
    /* Speed the release of some of these resources */
    threadLocals = null;
    inheritableThreadLocals = null;
    inheritedAccessControlContext = null;
    blocker = null;
    uncaughtExceptionHandler = null;
}
4、interrupt()-中斷方法
public void interrupt() {
    if (this != Thread.currentThread())
        // 如果是當前線程,就檢查是否有安全管理器
        // 如果有安全管理器就檢查權限
        checkAccess();

    // 加鎖,中斷blockerLock鎖
    synchronized (blockerLock) {
        // 設置中斷接口
        Interruptible b = blocker;
        if (b != null) {
            // 設置中斷標記
            interrupt0();           // Just to set the interrupt flag
            b.interrupt(this);
            return;
        }
    }
    // 調用本地native方法中斷
    interrupt0();
}
5、interrupted()-是否已中斷
// 判斷當前運行的線程是否中斷
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
// 判斷線程是否中斷
public boolean isInterrupted() {
    return isInterrupted(false);
}
// 本地native方法
private native boolean isInterrupted(boolean ClearInterrupted);
6、isAlive()是否被激活
  • 本地方法,public final native boolean isAlive();
7、yield()-暫停線程
  • 暫停一下線程,回到就緒狀態,讓出CPU資源,public static native void yield();
8、sleep - 2個方法
  • 會佔用CPU資源

9、join - 3個方法
  • 會釋放CPU資源
// 立即
public final void join() throws InterruptedException {
    join(0);
}
public final synchronized void join(long millis)
    throws InterruptedException {
    // 加鎖執行
    // 設置開始時間
    long base = System.currentTimeMillis();
    long now = 0;

    // 參數效驗,低於0 拋參數異常
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
	
    if (millis == 0) {
    	// 如果millis等於0,則判斷線程是否激活中,
        // 如果是就執行native方法Object.wait(0)使其等待
        while (isAlive()) {
            wait(0);
        }
    } else {
        // 循環判斷線程是否激活,
        while (isAlive()) {
            // 獲取當前還剩餘延遲時間
            long delay = millis - now;
            // 如果延遲時間超過了還沒休眠線程,則退出不休眠了
            if (delay <= 0) {
                break;
            }
            // 調用native方法Object.wait(delay) 使其等待
            wait(delay);
            // 更新已用休眠時間
            now = System.currentTimeMillis() - base;
        }
    }
}

public final synchronized void join(long millis, int nanos)
    throws InterruptedException {
    // 加鎖執行

    if (millis < 0) {
        // 毫秒邊界效驗
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        // 納秒邊界效驗
        throw new IllegalArgumentException(
            "nanosecond timeout value out of range");
    }

    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
        // 如果納秒 >= 500000 就把毫秒 + 1
        // 如果納秒 != 0 && millis == 0 就把毫秒 + 1
        millis++;
    }

    // 調用 join(long millis)
    join(millis);
}

補充

四、總結

  • 利用的操作系統來創建啓動線程,
  • 內含線程的啓動、休眠、阻塞、停止、中斷方法,還包含各種線程參數的獲取和判斷參數
發佈了48 篇原創文章 · 獲贊 17 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章