Java多线程--详解this与Thread.currentThread()的区别

时间:2021-08-11 17:32:27

注:本系列博客参考《Java多线程编程核心技术》,主要是对书上的知识点进行总结,并记录学习过程。

一直对并发这块比较感兴趣,也到了系统学习Java多线程的时间。目前所学习的书籍是《Java多线程编程核心技术》,买回来之后听说这本书不怎么样,豆瓣评分也就7点几,目前读完了第一章,感觉确实不是很好,但是也不算太坑,总的来说还是可以入手的。好了,废话不多说,开始正题。


首先我们来看一份代码:

public class CountOperate extends Thread {
public CountOperate() {
out.println("CountOperate---begin");
out.println("Thread.currentThread.getName()=" + Thread.currentThread().getName());
out.println("this.name()=" + this.getName());
out.println("Thread.currentThread()==this :"+ (Thread.currentThread() == this));
out.println("CountOperate---end");
}

@Override
public void run() {
out.println("run begin");
out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
out.println("this.getName=" + this.getName());
out.println("Thread.currentThread()==this :"+ (Thread.currentThread() == this));
out.println("run---end");
}
}
public class Run {
public static void main(String[] args) {
CountOperate countOperate = new CountOperate();
Thread thread = new Thread(countOperate);

thread.setName("A");
thread.start();
}
}

来看一下运行结果是否符合你的预期:

CountOperate---begin
Thread.currentThread.getName()=main
this.name()=Thread-0
Thread.currentThread()==this :false
CountOperate---end

run begin
Thread.currentThread().getName()=A
this.getName()=Thread-0
Thread.currentThread()==this :false
run---end

在还没有启动CountOperate线程的时候,调用这段代码的是main线程,所以:

Thread.currentThread.getName()=main

这是正常的,但是this.name()=Thread-0 这是个什么东西?看一下Thread源码吧:

public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}

参数的含义不明确?好,我们再来看一下init方法的声明:

 private void init(ThreadGroup g, Runnable target, String name, long stackSize)

来解释一下各个参数的含义:

  • ThreadGroup: 线程组
  • Runnable target: the object whose {@code run} method is invoked when this thread is started. If {@code null}, this thread’s run method is invoked. (源码解释,建议百度翻译,也是产生this和Thread.currentThread区别的原因)因为在Thread源码中,Thread实际上操作了Runable,所以此参数也接受Thread对象,也就是说此参数也可以是继承了Thread的线程类
  • String name: 线程名
  • long stackSize: 新线程所需的堆栈大小,或0表示该参数将被忽略。

这下,我们知道Thread-0是怎么来的了,String name生成名称的规则是:“Thread-”加上创建的线程的个数(第几个)。默认从0开始,main线程是默认就有的,所以并不计数。

然后Thread.currentThread()==this :false 这个也好理解,this代表的是CountOperate对象实例,而Thread.currentThread() 得到的是main,所以为false。

代码继续向下执行… …

重点来了:

Thread.currentThread().getName()=A
this.getName()=Thread-0
Thread.currentThread()==this :false

Thread.currentThread().getName() 得到的是执行这段代码的线程名,我们已经设置为了A,没问题。但是这里的this.getName()=Thread-0为什么没变?this代表的实例是什么?别着急,我们再来看一看源码:

public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}

然后我们结合上面源码中target的注释再来看一看run方法的源码:

public void run() {  
if (target != null) {
target.run();
}
}

明白了吧?只要target不为空,那么它最后还是会调用target的run方法。是的,现在问题已经解决了!没反应过来?那我们回过头来看一下Thread thread = new Thread(countOperate),从源码来讲,它最后还是会执行countOperate.run(),而this取得的就是代表当前实例的引用,所以,this.getName() 还是会打印Thread-0。那么最后一个false也就明白了,两个取得的都不是同一个对象,自然Thread.currentThread()和this也就不等了。