Thread.currentThread()与this的区别,以及super.run()的作用

薛定谔的Bug
• 阅读 1715

一 Thread.currentThread()与this
本文讨论Thread.currentThread()与this不一样的情况。
在将线程对象以构造参数的方式传递给Thread对象进行start()启动时,Thread.currentThread()与this的取值是不一样的。
代码:

package springboot.myrunable;

/**

  • @author liuhongya328
    *
    */

public class CountOperate extends Thread {

/**
 * 构造方法
 */
public CountOperate() {
    System.out.println("count-----begin");
    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());
    System.out.println("count-----end");
}

@Override
public void run() {
    System.out.println("run-----begin");
    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());
    System.out.println("run-----end");
}

}

测试类:

package springboot.myrunable;

/**

  • @author liuhongya328
    *
    */

public class TestThread {

/**
 * @param args
 */
public static void main(String[] args) {
    CountOperate cc = new CountOperate();
    Thread t1 = new Thread(cc);
    System.out.println("main begin t1 isalive="+t1.isAlive());
    t1.setName("A");
    t1.start();
    System.out.println("main end t1 isalive="+t1.isAlive());
}

}

运行结果:

count-----begin
Thread.currentThread().getName()=main
Thread.currentThread().isAlive()=true
this.getName()=Thread-0
this.isAlive()=false
count-----end
main begin t1 isalive=false
main end t1 isalive=true
run-----begin
Thread.currentThread().getName()=A
Thread.currentThread().isAlive()=true
this.getName()=Thread-0
this.isAlive()=false
run-----end

说明:
1.先看Test类
public static void main(String[] args) {
//main函数进程开始-name为main

//创建了一个cc的线程,线程为新建状态。线程名为Thread0
CountOperate cc = new CountOperate();
//创建了一个t1的线程,线程为新建状态。线程名为Thread1
Thread t1 = new Thread(cc);
System.out.println("main begin t1 isalive="+t1.isAlive());
//将Thread1的名字改为A
t1.setName("A");
//Thread1(A)启动,线程状态变为就绪
t1.start();
System.out.println("main end t1 isalive="+t1.isAlive());

}

2.再看实现类

/**

 * 构造方法
 */
public CountOperate() {
    System.out.println("count-----begin");
    //构造方法是main方法在执行
    System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
    System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
    //当前线程的name,在new CountOperate()的时候已经创建了cc线程,name为Thread0
    System.out.println("this.getName()=" + this.getName());
    System.out.println("this.isAlive()=" + this.isAlive());
    System.out.println("count-----end");
}


@Override
public void run() {
    System.out.println("run-----begin");
    //run方法是t1方法在执行,t1.getName()为Thread1(A)的名称
    System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName());
    System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive());
    

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

    //上面是t1的构造函数,传入的对象实际上是指向cc,所以this.getName()是cc的name-->Thread0
    System.out.println("this.getName()=" + this.getName());
    System.out.println("this.isAlive()=" + this.isAlive());

    //加入这个可能会让理解更好点。
    System.out.println("this.currentThread().getName()=" + this.currentThread().getName());
    
    System.out.println("run-----end");
}

注释很详细,欢迎交流!

二 super.run();
首先,我们来看一下JDK的Thread源码

private Runnable target;
public void run() {

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

}

代码1:

new Thread(new Runnable() {

@Override  
public void run() {  
    System.out.println("Run of Runnable");  
}  

}) {

public void run() {  
    System.out.println("Run of Thread");  
}  

}.start();

代码2:

new Thread(new Runnable() {

@Override  
public void run() {  
    System.out.println("Run of Runnable");  
}  

}) {

public void run() {  
    System.out.println("Run of Thread");  
    super.run();  
}  

}.start();

在run()方法中,首先会检查target是否为空,如果不是,则执行该target的run()方法。

那么,对于上面两段代码的执行,也就清楚了。

在第一个代码段 1 中,重写了Thread的run()方法,同时传入了一个Runnable对象,该对象也实现了run()方法。该Thread对象调用start()方法后,会执行该对象重写的run()方法,其输出结果也就是Run of Thread,输出完后,run()方法返回,该线程对象的生命周期也就结束了。

在第二个代码段 2 中,同样也重写了Thread的run()方法,同时传入了一个Runnable对象,实现了run()方法。唯一不同的是,在Thread重写的run方法中,在打印输出后,还执行了super.run(),这就有意思了。

首先,该线程启动运行后,执行其重写的run()方法,输出Run of Thread。

接下来调用super.run(),也就是调用超类的run()方法,而该超类的run()方法,也就是JDK定义的Thread类的run(),其执行如上代码段 3 所示;显然target不为空,这时候会调用该对象的run()方法,会输出Run of Runnable.。

如果,上面的Thread并未重写run()方法,那么,执行的结果还是一样。首先会执行该Thread的run()方法,因为此时并未重写该方法,所以还是会调用JDK定以的run()方法,也就是上面的代码段 3,在该代码段中会判断target是否为空,显然不是,所以会调用Runnable对象实现的run()方法。

总结:

对于Thread(Runnable target ...),不管传入的Target是否为空,首先都会执行Thread自己的run()方法。

如果重写了该方法且该方法中没有super.run(),那么是永远不会调用Runnable实现的run()方法;

如果没有重写该方法,则会去判断target是否为空,以此来决定调用target实现的run()方法;

如果重写了该方法,且该方法中有super.run(),如代码2,在执行完该语句之前的所有代码后,会判断target是否为空,以此来决定调用target实现的run()方法,执行完后,接着执行该语句之后的代码。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
java 复制Map对象(深拷贝与浅拷贝)
java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
java 多线程
创建线程的4种方式1、继承Thread类,复写run方法,run方法中为线程需要执行的逻辑部分,而启动线程调用start方法。小示例见代码,通过Thread.currentThread().getName()可以获得当前线程名称publicclassMyThreadextendsThread{private
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
Noark入门之线程模型
0x00单线程多进程单线程与单进程多线程的目的都是想尽可能的利用CPU,减少CPU的空闲时间,特别是多核环境,今天咱不做深度解读,跳过...0x01线程池锁最早的一部分游戏服务器是采用线程池的方式来处理玩家的业务请求,以达最大限度的利用多核优势来提高处理业务能力。但线程池同时也带来了并发问题,为了解决同一玩家多个业务请求不被
Easter79 Easter79
3年前
ThreadLocal的深入理解及应用
是什么?ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,它类似(Map),用来存储当前运行线程及对应的变量。在WEB应用中每次Http请求,都相当于从线程池取一个空闲线程对请求的方法作处理。此时当前线程的所有方法中Thread.currentThread
Wesley13 Wesley13
3年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Easter79 Easter79
3年前
Thread.interrupt()源码跟踪
1JDK源码跟踪//java.lang.Threadpublicvoidinterrupt(){if(this!Thread.currentThread())checkAccess();synchronized(blockerLock)