引言
首先來看下下面這段代碼赛蔫。這是一段簡單的中斷線程的示例代碼纲仍。
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()” 引發(fā)了我的思考:“既然該Runner的對象正在作為線程運行雏赦,那 this 和 Thread.currentThread() 不也就是同一個對象灌侣,為什么不直接用this呢后频?眉抬,相比之下this更加簡短吴藻÷髋溃”
在上面這段段代碼中,將 Thread.currentThread() 替換成 this沟堡,是等同的侧但,運行結(jié)果相同,能正常退出航罗。
而下面代碼禀横,this 和 Thread.currentThread() 則運行結(jié)果則不同。this 會出現(xiàn)死循環(huán)粥血,無法退出柏锄;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 類的內(nèi)部實現(xiàn)有關(guān)趾娃。
正文
在直接揭秘兩者區(qū)別之前,先來了解下 Thread 類的內(nèi)部實現(xiàn)缔御。
Runner的中實現(xiàn)了構(gòu)造函數(shù)抬闷,main方法中只創(chuàng)建了 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
**/
根據(jù)前兩行輸出笤成,可以看出评架,“當(dāng)前的執(zhí)行線程是 main 線程,并且處于運行狀態(tài)”炕泳,容易理解纵诞。
再看后兩行輸出,this 指向的是新建的 runner 實例喊崖,該實例的 name 屬性為 “Thread-0”挣磨,并且沒有運行。沒有運行很容易理解荤懂,因為沒有執(zhí)行 runner.start() 方法茁裙。關(guān)于 name 屬性為何是 “Thread-0”,這是在創(chuàng)建 Thread 實例時节仿,初始化的名字晤锥。
下面是 Thread類 的構(gòu)造函數(shù),其中 init() 方法第三個參數(shù)為線程的默認(rèn)名字廊宪。生成名稱的規(guī)則是:“Thread-”加上創(chuàng)建的線程的個數(shù)(第幾個)矾瘾。默認(rèn)從0開始,由于main線程是默認(rèn)就有的箭启,所以并不計數(shù) 壕翩。
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
所以 runner.getname() 得到的結(jié)果是 "Thread-0"。
接下來再看一段代碼傅寡。新建 Runner 實例對象 runner放妈。由于 Runner 是 Thread 的子類,并且 Thread 實現(xiàn)了 Runnable 接口荐操,所以可以作為 Thread 類的構(gòu)造函數(shù)參數(shù)傳入芜抒。將 runner 作為構(gòu)造函數(shù)參數(shù)傳入,創(chuàng)建 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”(第二個被創(chuàng)建)拐迁,并且處于運行狀態(tài)。
再來看看后兩行輸出肩民,可看出 this 指向的是 runner 對象唠亚,其name為“Thread-0”,并且沒有運行持痰。
為什么 this 不是指向 thread 呢灶搜??? 不是 thread 在運行嗎割卖?前酿??
其原因在于 Thread thread = new Thread(runner)
會將 runner 對象綁定到 thread 對象的一個 pravite 變量target 上鹏溯,在 thread 被執(zhí)行的時候即 thread.run() 被調(diào)用的時候罢维,它會調(diào)用 target.run() 方法,也就是說它是直接調(diào)用 runner 對象的run方法丙挽。
再確切的說肺孵,在run方法被執(zhí)行的時候,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();
}
}
總結(jié)
正在執(zhí)行線程中的 this 對象并非就一定是該執(zhí)行線程,因為執(zhí)行線程的 run方法 可能是直接調(diào)用 其他Runnabel對象的 run() 方法凳怨。
個人看法瑰艘,不要在線程中用 this 來表示當(dāng)前運行線程,不可靠肤舞。