【併發編程】Thread類的詳細介紹


本博客系列是學習併發編程過程當中的記錄總結。因爲文章比較多,寫的時間也比較散,因此我整理了個目錄貼(傳送門),方便查閱。html

併發編程系列博客傳送門java


Thread類是Java中實現多線程編程的基礎類。本篇博客就來介紹下Thread類的經常使用API和常見用法。編程

Thread類經常使用的方法以下:數據結構

  • Thread.activeCount():這個方法用於返回當前線程的線程組中活動線程的數量,返回的值只是一個估計值,由於當此方法遍歷內部數據結構時,線程數可能會動態更改。)。
  • Thread.checkAccess(): 檢驗當前正在執行的線程是否有權限修改thread的屬性,這個方法咱們通常不本身進行調用,Thread類的set方法在進行屬性修改時都會先調用這個方法。
  • Thread.currentThread():獲取當前正在運行的線程。
  • Thread.dumpStack():輸出線程棧,通常在debug的時候調用。
  • Thread.enumerate(Thread tarray[]):??使用場景。
  • Thread.getAllStackTraces():獲取系統中全部線程的線程棧信息。
  • thread.getName():獲取線程的名字。
  • thread.getPriority():獲取線程的優先級。
  • thread.getStackTrace():獲取堆棧信息。
  • thread.getState():獲取線程狀態。
  • thread.getThreadGroup():獲取線程所在線程組。
  • thread.interrupt():使得指定線程中斷阻塞狀態,並將阻塞標誌位置爲true。
  • thread.interrupted():測試當前線程是否被中斷。
  • thread.isAlive():判斷線程是否還存活着。
  • thread.isDaemon():判斷線程是不是守護線程。
  • thread.join():在當前線程中加入指定線程,使得當前線程必須等待指定線程運行結束以後,才能結束。能夠理解成線程插隊、等待該線程終止。
  • Thread.sleep(long):強制線程睡眠一段時間。
  • thread.start():啓動一個線程。
  • thread.setName(name):設置線程的名字。
  • thread.setPriority(priority):設置線程的優先級。
  • thread.setDaemon(true):將指定線程設置爲守護線程。
  • thread.yield():使得當前線程退讓出CPU資源,把CPU調度機會分配給一樣線程優先級的線程。
  • object.wait()、object.notify()、object.notifyAll():Object類提供的線程等待和線程喚醒方法。

還有Thread類提供了功能豐富的構造函數,你們能夠選合適的使用多線程

示例代碼

public class MyThread  {

    public static void main(String[] args) {
          Thread thread = Thread.currentThread();
        
                //這個方法返回的是當前線程所在線程組以及這個線程組的子線程組內活動的線程數
                //這個值是一個估計值,因此這個方法的應用場景不大
                int activeCount = Thread.activeCount();
                System.out.println("當前系統中活動線程數["+activeCount+"]");
        
                //向標準錯誤輸出流輸出當前的線程棧,不會阻斷程序的繼續執行
                Thread.dumpStack();
        
                //獲取全部線程棧信息
                Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
        
                //獲取類加載器
                ClassLoader contextClassLoader = thread.getContextClassLoader();
        
                //獲取當前線程名字
                String threadName = thread.getName();
                System.out.println("current thread name["+threadName+"]");
        
                //獲取當前線程ID
                long threadId = thread.getId();
                System.out.println("current thread id["+threadId+"]");
        
                //獲取當前線程的優先級,一共有1~10總共10個優先級,這個優先級並非在
                //全部平臺都生效的
                int priority = thread.getPriority();
                System.out.println("current thread priority["+priority+"]");
        
                StackTraceElement[] stackTrace = thread.getStackTrace();
                System.out.println("-------------stackTrace info--------------");
                for (int i = 0; i < stackTrace.length; i++) {
                    StackTraceElement element = stackTrace[i];
                    System.out.println("className:["+element.getClassName()+"]");
                    System.out.println("fileName:["+element.getFileName()+"]");
                    System.out.println("line nunber:["+element.getLineNumber()+"]");
                    System.out.println("method name:["+element.getMethodName()+"]");
                    System.out.println("is native method:["+element.isNativeMethod()+"]");
                    System.out.println("------------------------------------------");
                }
        
                Thread.State state = thread.getState();
                System.out.println("thread state:["+state+"]");
        
                ThreadGroup threadGroup = thread.getThreadGroup();
                String threadGroupName = threadGroup.getName();
                System.out.println("thread group name:["+threadGroupName+"]");
        
                //線程睡眠,調用sleep方法會使得線程進入timed_waiting狀態,若是線程已經
                //得到了鎖資源,調用sleep方法是不會釋放這個鎖的
                Thread.sleep(2000,500);
                Thread.sleep(1000);
                TimeUnit.SECONDS.sleep(2);
        
                Thread thread1 = new Thread(new Runnable() {
                    @SneakyThrows
                    @Override
                    public void run() {
                        TimeUnit.SECONDS.sleep(100);
                    }
                });
                thread1.start();
                thread1.join(50);

    }


}

守護線程

守護線程能夠理解爲服務線程,他們的做用就是服務於其餘用戶線程。當系統中不存在其餘用戶線程時,這些守護線程也會自動消亡。好比JVM的垃圾清理線程就是守護線程。咱們可使用以下方法查看和設置線程是不是守護線程。併發

thread.isDaemon();
thread.setDaemon(true);

join方法

開發過程當中咱們可能會有這樣的需求:多個線程分別加載資源,等這些線程資源加載完畢以後對這些資源作統一彙總處理。join方法就能實現相似的功能。ide

調用線程的join方法會使得調用線程進入waiting狀態,直到被調用的線程執行結束,調用線程纔會從新得到執行的機會。函數

public class MyThread  {

    public static void main(String[] args) throws Exception {
    
        Thread thread1 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                TimeUnit.SECONDS.sleep(100);
            }
        });
        thread1.start();
        thread1.join();
        System.out.println("main thread end...");
    }

}

上面的代碼中,main線程調用了thread1的join方法,main線程會被掛起進入waiting狀態,直到thread1執行完畢以後,main線程纔有機會從新得到執行機會。學習

join方法還有一個重載方法,這個方法能夠指定超時時間。測試

thread1.join(50);

若是thread1線程在50ms內還沒執行完,main線程就能夠從新得到執行機會。

yeild方法

調用線程的yield方法是在暗示讓這個線程讓出CPU資源,若是這個線程在執行一個CPU時間,已經執行到一半了,調用yield以後這個線程會放棄剩下的一半CPU時間回到就緒狀態。可是須要注意的是線程能夠徹底忽略yield方法的調用,也就是yield方法並非每次都調用成功的:

  • 退讓成功時,退讓線程會由Running(運行)轉爲Runnable(就緒)狀態。
  • 退讓了的線程,與其餘同優先級級別的線程同樣,一樣有再次獲取CPU使用權的機會。

中斷

先貼上一段網友對線程中斷的總結。

  • 若是線程不處於阻塞狀態,那麼調用interrupt()方法僅僅是將[中斷標誌位]將被置爲true;
  • 若是當前線程處於blocked阻塞(由於調用wait、sleep和join形成的)狀態時被interrupt了,那麼[中斷標誌位]將被清除,也就是設置爲false,而且收到一個InterruptedException異常。
  • 若是當前線程處於blocked阻塞(由於NIO的InterruptibleChannel進行的I/O操做形成的)狀態時被interrupt了,則會關閉channel,[中斷標誌位]將會被置爲true,而且當前線程會收到一個ClosedByInterruptException異常。
  • 若是當前線程處於blocked阻塞(由於NIO的Selector形成的)狀態時被interrupt了,那麼[中斷標誌位]將被置爲true,而後當前線程會當即從選擇器區域返回並返回值(可能爲非零的值)。

須要說明的是:interrupt()方法並非中斷線程,而是中斷阻塞狀態,或者將線程的[中斷標誌位]置爲true。中斷後線程將繼續執行。

幾個中斷方法對比:

  • public static boolean interrupted():測試當前線程(這邊要注意的是這個方法返回的是當前正在執行的線程的中斷狀態)是否已經中斷。線程的中斷狀態 由該方法清除。換句話說,若是連續兩次調用該方法,則第二次調用將返回 false。
  • public boolean isInterrupted():測試線程是否已經中斷。線程的中斷狀態 不受該方法的影響。
  • public void interrupt():中斷線程。
相關文章
相關標籤/搜索