引言
首先來看下下面這段代碼。這是一段簡單的中斷線程的示例代碼。
public class Test {
static class Runner extends Thread {
@Override
public void run() {
while (true) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("Interruted!");
break;
}
}
}
}
public static void main(String[] args) {
Runner runner = new Runner();
runner.start();
runner.interrupt();
}
}
其中的 “Thread.currentThread()” 引發了我的思考:“既然該Runner的對象正在作爲線程運行,那 this 和 Thread.currentThread() 不也就是同一個對象,爲什麼不直接用this呢?,相比之下this更加簡短。”
在上面這段段代碼中,將 Thread.currentThread() 替換成 this,是等同的,運行結果相同,能正常退出。
而下面代碼,this 和 Thread.currentThread() 則運行結果則不同。this 會出現死循環,無法退出;Thread.currentThread() 能正常退出。
public class Test {
static class Runner extends Thread {
@Override
public void run() {
while (true) {
if (this.isInterrupted()) {
System.out.println("Interruted!");
break;
}
}
}
}
public static void main(String[] args) {
Runner runner = new Runner();
Thread thread = new Thread(runner);
thread.start();
thread.interrupt();
}
}
這說明 this 和 Thread.currentThread() 並不能完全等同。
其原因主要跟 Thread 類的內部實現有關。
正文
在直接揭祕兩者區別之前,先來了解下 Thread 類的內部實現。
Runner的中實現了構造函數,main方法中只創建了 runner 實例,並沒有啓動線程。
public class Test {
static class Runner extends Thread {
public Runner() {
System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
System.out.println("this.getName=" + this.getName());
System.out.println("this.isAlive()=" + this.isAlive());
}
}
public static void main(String[] args) {
Runner runner = new Runner();
}
}
/** output
Thread.currentThread().getName()=main
Thread.currentThread().isAlive()=true
this.getName=Thread-0
this.isAlive()=false
**/
根據前兩行輸出,可以看出,“當前的執行線程是 main 線程,並且處於運行狀態”,容易理解。
再看後兩行輸出,this 指向的是新建的 runner 實例,該實例的 name 屬性爲 “Thread-0”,並且沒有運行。沒有運行很容易理解,因爲沒有執行 runner.start() 方法。關於 name 屬性爲何是 “Thread-0”,這是在創建 Thread 實例時,初始化的名字。
下面是 Thread類 的構造函數,其中 init() 方法第三個參數爲線程的默認名字。生成名稱的規則是:“Thread-”加上創建的線程的個數(第幾個)。默認從0開始,由於main線程是默認就有的,所以並不計數 。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
所以 runner.getname() 得到的結果是 “Thread-0”。
接下來再看一段代碼。新建 Runner 實例對象 runner。由於 Runner 是 Thread 的子類,並且 Thread 實現了 Runnable 接口,所以可以作爲 Thread 類的構造函數參數傳入。將 runner 作爲構造函數參數傳入,創建 Thread 實例對象 thread,啓動 thread。
public class Test {
static class Runner extends Thread {
@Override
public void run() {
System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
System.out.println("this.getName=" + this.getName());
System.out.println("this.isAlive()=" + this.isAlive());
}
}
public static void main(String[] args) {
Runner runner = new Runner();
Thread thread = new Thread(runner);
thread.start();
}
}
/** output
Thread.currentThread().getName()=Thread-1
Thread.currentThread().isAlive()=true
this.getName=Thread-0
this.isAlive()=false
**/
首先看下前兩行輸出,可看出 Thread.currentThread() 指向 thread 對象,其name爲“Thread-1”(第二個被創建),並且處於運行狀態。
再來看看後兩行輸出,可看出 this 指向的是 runner 對象,其name爲“Thread-0”,並且沒有運行。
爲什麼 this 不是指向 thread 呢??? 不是 thread 在運行嗎???
其原因在於 Thread thread = new Thread(runner)
會將 runner 對象綁定到 thread 對象的一個 pravite 變量target 上,在 thread 被執行的時候即 thread.run() 被調用的時候,它會調用 target.run() 方法,也就是說它是直接調用 runner 對象的run方法。
再確切的說,在run方法被執行的時候,this.getName() 實際上返回的是 target.getName(),而Thread.currentThread().getName() 實際上是 thread.getName()。
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
總結
正在執行線程中的 this 對象並非就一定是該執行線程,因爲執行線程的 run方法 可能是直接調用 其他Runnabel對象的 run() 方法。
個人看法,不要在線程中用 this 來表示當前運行線程,不可靠。