Thread.currentThread().getName() 和 this.getName()區別詳解

經典雞翅發表於2022-02-20

currentThread的詳解

currentThread方法是Thread類的一個靜態方法,用來獲取當前執行的程式碼段,正在被哪個執行緒呼叫。我們先來看一眼原始碼。

是一個native方法。直接與系統層面做互動。
下面看一段程式碼

    public static void main(String[] args) {
        String name = Thread.currentThread().getName();
        System.out.println(name);
    }

輸出的結果為main。

為什麼為main呢?

java的專案在啟動的時候,會創立一個程式,這個程式同樣也是一個執行緒,在java裡面他就叫做main執行緒。他的名字在設定的時候就是main。我們可以看到上面的程式碼就是在main方法下執行的,也就是由main執行緒來執行,所以我們列印出來的名字是main。

建立一個新的執行緒

來看下面的一行程式碼,我們建立一個新的執行緒,並且線上程建立的構造方法和其實際執行的run方法內,增加列印出當前執行執行緒的名稱。

public class TestThread extends Thread {

    public TestThread() {
        System.out.println("構造方法:" + Thread.currentThread().getName());
    }

    @Override
    public void run() {
        System.out.println("run方法:" + Thread.currentThread().getName());
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.start();
    }

}

我們執行一下,看到結果

構造方法:main
run方法:Thread-0

如何理解上述的情況呢?

我們先來看構造方法這一行。

TestThread testThread = new TestThread();

這裡我們只是宣告瞭一個執行緒物件類,這個新的執行緒沒有建立也沒有啟動,我們僅僅把它理解為一個普通物件即可。那麼由於是在main方法裡面,那麼執行他的一定是main執行緒,所以可以看到構造方法輸出的結果是main。
再來看start方法裡面,為什麼變成了thread-0了呢。
我們知道java的多執行緒建立的一種方式就是繼承thread類。然後實現裡面的run方法。這樣當執行緒start的時候,就會呼叫內部的start0的本地方法,實際就是會執行run的實現方法。當run方法執行的時候,一定是由我們建立的執行緒去執行的,而不是main執行緒,所以我們就可以得知列印出來的是新執行緒的名字thread0。

為什麼新執行緒的名字為thread0呢?

我們是採用繼承thread類的形式來建立執行緒的,那麼在我們構造的時候,一定會執行父類的構造方法。我們是一個空參構造,那麼我們就要看下父類的空參構造是什麼樣的。看一下原始碼

可以看到,裡面有一個name引數,已經給我們拼接了一個thread-後面是加了一個變數,我們繼續看看這個變數是什麼

一個同步的靜態方法,再來看看變數的值。

一個靜態的int型變數,由此我們知道int的初始值就是0。我們先獲取到了0然後又執行了++。其他執行緒再次初始化的時候就是從1開始了。因為加了同步鎖的關鍵字,我們不用害怕資料會亂掉。
所以我們就知道了新執行緒的名字為thread-0的來源。

再看一種帶this的情況

public class TestThread extends Thread {

    public TestThread() {
        System.out.println("構造方法開始!");
        System.out.println("構造方法:" + Thread.currentThread().getName());
        System.out.println("構造方法的this名稱:" + this.getName());
        System.out.println("構造方法結束!");
    }

    @Override
    public void run() {
        System.out.println("run方法開始!");
        System.out.println("run方法:" + Thread.currentThread().getName());
        System.out.println("run方法的this名稱:" + this.getName());
        System.out.println("run方法結束!");
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.start();
    }

}

執行的結果如下:

構造方法開始!
構造方法:main
構造方法的this名稱:Thread-0
構造方法結束!
run方法開始!
run方法:Thread-0
run方法的this名稱:Thread-0
run方法結束!

我們發現構造的this名稱 為thread-0。這個不難理解,this指的是當前物件的名稱。因為我們的執行緒在初始化的時候有了name,所以是thread-0。

建立的執行緒setName的情況

public class TestThread extends Thread {

    public TestThread() {
        System.out.println("構造方法開始!");
        System.out.println("構造方法:" + Thread.currentThread().getName());
        System.out.println("構造方法的this名稱:" + this.getName());
        System.out.println("構造方法結束!");
    }

    @Override
    public void run() {
        System.out.println("run方法開始!");
        System.out.println("run方法:" + Thread.currentThread().getName());
        System.out.println("run方法的this名稱:" + this.getName());
        System.out.println("run方法結束!");
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        testThread.setName("test");
        testThread.start();
    }

}

看一下執行的結果

構造方法開始!
構造方法:main
構造方法的this名稱:Thread-0
構造方法結束!
run方法開始!
run方法:test
run方法的this名稱:test
run方法結束!

這裡有人可能就要問了,為啥構造方法的this名稱為thread-0。實際run的時候就變為test了呢。
這是因為我們在構造物件的時候,物件還不完整,沒有執行到setName這一步。所以二者不一致。

最後看一段複雜的程式碼

public class TestThread extends Thread {

    public TestThread() {
        System.out.println("構造方法開始!");
        System.out.println("構造方法:" + Thread.currentThread().getName());
        System.out.println("構造方法的this名稱:" + this.getName());
        System.out.println("構造方法結束!");
    }

    @Override
    public void run() {
        System.out.println("run方法開始!");
        System.out.println("run方法:" + Thread.currentThread().getName());
        System.out.println("run方法的this名稱:" + this.getName());
        System.out.println("run方法結束!");
    }

    public static void main(String[] args) {
        TestThread testThread = new TestThread();
        Thread thread = new Thread(testThread);
        System.out.println("新執行緒thread的名稱:" + thread.getName());
        thread.setName("test");
        thread.start();
    }

}

可以看到如下的結果

構造方法開始!
構造方法:main
構造方法的this名稱:Thread-0
構造方法結束!
新執行緒thread的名稱:Thread-1
run方法開始!
run方法:test
run方法的this名稱:Thread-0
run方法結束!

我們根據結果來看,構造方法的列印,和上面解釋的如出一轍。我們重點關注一下新執行緒的列印,這裡為什麼是1呢,因為我們上面初始化0之後已經++所以為1。
run方法為test是因為我們實際執行的執行緒Thread thread = new Thread(testThread);所以我們獲取到的名稱是thread的名稱為test。
那麼run方法的this名稱為什麼是thread-0呢。因為this.getName獲取到的是當前物件的名稱。我們的當前物件是TestThread。他的執行緒名稱從未被改變過,所以我們拿到了thread-0。

總結

currentThread的getName代表當前執行執行緒的名稱,this.getName代表物件的名稱。this.getName()實際上返回的是target.getName(),而Thread.currentThread().getName()實際上是thead.getName()。

相關文章