併發編程之線程屬性

  本文主要討論線程的各類屬性,包括:主線程、線程優先級、守護線程、線程組、處理未捕獲異常的處理器。java

 
主線程
 
  任何一個Java程序啓動時,至少會啓動一個線程執行main方法,這個線程就被稱爲主線程(Main Thread)。它是產生其它線程的線程,即:其它全部線程的主線程的子孫線程。一般,主線程都是最後結束的,由於它要執行其它子線程的關閉工做。
 
線程優先級
 
  計算機只有一個CPU,各個線程輪流獲取CPU的使用權,才能執行任務。爲了判斷優先執行哪一個線程,給每個線程設置了一個優先級,優先級高的線程將會被優先執行。默認狀況下,每一個線程的優先級繼承它的父線程(建立該線程的線程)的優先級。優先級是1-10之間的整數,通常狀況下,線程默認的優先級是5。經常使用的優先級有三個(1 : MIN_PRIORITY、 5 : NORM_PRIORITY、 10 : MAX_PRIORITY)。
public class Priority {


    @Test
    public void defaultPriority(){
        int mainThreadPriority = Thread.currentThread().getPriority();
        System.out.println("default priority is "+mainThreadPriority);//5
    }


    @Test
    public void extendFather(){
        Thread mainThread = Thread.currentThread();
        mainThread.setPriority(4);
        int mainThreadPriority = mainThread.getPriority();
        System.out.println("main thread's priority is "+mainThreadPriority);//4
        Thread t1 = new Thread(() -> System.out.println(Thread.currentThread().getName()),"t1");
        System.out.println("t1 thread's priority is "+t1.getPriority());//4
    }
}

相關API:數據庫

void setPriority(int priority)    設置線程優先級
int getPriority()             獲取線程優先級

備註:ide

  1. 不要讓業務依賴於線程優先級。(優先級只能讓線程獲取更多的機會優先執行,但不一是必定會優先執行)spa

  2. 通常狀況下,不會對線程設定優先級線程

 

守護線程code

    守護線程(Daemon Thread)的惟一做用就是爲其它線程提供服務,永遠不要在守護線程中訪問固有資源,好比文件、數據庫等。
 
 守護線程可以結束本身的生命週期,即:當全部的用戶線程都結束後,守護線程就會結束。且當只剩下守護線程,虛擬機就會退出。
 
 守護線程通常用來處理一些後臺工做(好比JDK的垃圾回收線程),所以有時也被稱爲後臺線程。
 
    默認狀況下,由用戶線程建立的線程還是用戶線程,由守護線程建立的線程還是守護線程。
 
    Java虛擬機的垃圾回收線程就是典型的守護線程。
 
    相關API:
void setDaemon(boolean isdaemon) 設置線程爲守護線程或者用戶線程。該方法必須在線程啓動以前調用。
boolean isDaemon()          判斷該線程是否爲後臺線程

 

線程組對象

    線程組(Thread Group)是一個能夠統一管理的線程集合,線程組也能夠包含其它線程組。默認狀況下,全部的線程屬於同一個線程組。線程只能訪問本身所在線程組的信息,不能訪問其它線程組的信息,包括該線程組的父線程組。
 
    建議不要使用線程組(已經有更好的特性用於線程集合的操做)
public class ThreadGroupDemo {

    public static void print(){
        Thread thread = Thread.currentThread();
        System.out.println(thread.getThreadGroup().getName()+"-"+thread.getName());
    }
    
    public static void main(String[] args) {
        ThreadGroup group = new ThreadGroup("Print Group");
        new Thread(group, ThreadGroupDemo::print, "t1").start();
        new Thread(group, ThreadGroupDemo::print, "t2").start();
        group.list();

    }
}

 補充:blog

  • 線程組並不能提供對線程的管理,主要是用來組織線程
  • 線程組中的線程優先級不能大於該線程組的優先級
  • interrupt一個線程組,會致使線程組中的全部active線程都被interrupt
  • 若是線程組被設置爲daemon,當線程組中沒有active線程,線程組將自動銷燬

 

未捕獲異常處理器繼承

  線程的run()不能拋出任何被檢測的異常【由於Runnable接口中定義的run()沒有拋出異常,因此重寫run()時,不容許拋出異常,可使用try-catch捕獲異常】。可是,若是不被檢測的異常沒有使用try-catch處理,發生異常時會致使線程死亡。(好比下面這個例子,控制檯並無輸出「Endind?」)接口

public class UncaughtExceptionDemo implements Runnable{

    @Override
    public void run() {
        int i = 1/0;
        System.out.println("Endind?");
    }


    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.execute(new UncaughtExceptionDemo());
    }
}

/* log:
...
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
    at concurrency.attributes.UncaughtExceptionDemo.run(UncaughtExceptionDemo.java:10)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
*/

  並且,在run中手動拋出了一個運行時異常,在main中使用try-catch處理異常,並未生效。(以下例,控制檯並未輸出"Current thread occurs exception.")

public class UncaughtExceptionDemo implements Runnable{

    @Override
    public void run() {
        int i = 1/0;
    }


    public static void main(String[] args) {
        try{
            ExecutorService service = Executors.newFixedThreadPool(1);
            service.execute(new UncaughtExceptionDemo());
        } catch (RuntimeException e){
            System.out.println("Current thread occurs exception.");
        }
    }
}

/*
...
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
    at concurrency.attributes.UncaughtExceptionDemo.run(UncaughtExceptionDemo.java:10)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
*/

   那麼,應該如何處理線程中拋出的異常呢?事實上,異常發生後,在線程死亡以前,異常會被傳遞到一個用於未捕獲異常的處理器。可使用該處理器來處理線程中拋出的異常。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ThreadExceptionResolve implements Runnable{


    @Override
    public void run() {
        int i = 1/0;
        System.out.println("Endind?");
    }


    public static void main(String[] args) {
        //2. 爲全部的線程設置「異常處理器」
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        //3. 建立並執行線程
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.execute(new ThreadExceptionResolve());
    }
}


//1. 定義符合線程異常處理器規範的「異常處理器」
// 該處理器必須屬於一個實現Thread.UncaughtExceptionHandler接口的類
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {


    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("The acculation is error.");
    }
}

/*
...
The acculation is error.
*/

  安裝處理器的方式有兩種:可使用Thread的靜態方法setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)爲全部線程設置默認處理器,也可使用Thread的實例方法setUncaughtExceptionHandler(UncaughtExceptionHandler eh)爲摸一個線程設定處理器。若是線程沒有安裝處理器,此時的處理器就是該線程的ThreadGroup對象。

//爲全部線程設置默認處理器
Thread.setDefaultUncaughtExceptionHandler(handler);


//爲指定線程設置處理器
Thread mainThread = Thread.currentThread();
mainThread.setUncaughtExceptionHandler(handler);
相關文章
相關標籤/搜索