继承Thread与实现Runnable时this != currentThread()判断差异原因咨询
问题:继承Thread与实现Runnable时
this != currentThread()判断的行为差异 我希望通过this != currentThread()判断当前是否未处于main线程,但发现继承Thread类与实现Runnable接口时行为存在差异:
继承Thread类的代码(可正常运行)
public class Demo { public static void main(String[] arg) { MyThread a = new MyThread(); a.start(); a.run(); } private static class MyThread extends Thread { @Override public void run() { if (this != currentThread()) { throw new IllegalStateException("run() must not be called directly"); } System.out.println(getName() + " run started..."); for (int i = 1; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { System.out.println(e.getMessage()); } } System.out.println('\n' + getName() + " run ended."); } } }
实现Runnable接口的代码(执行start()时抛出异常)
import static java.lang.Thread.currentThread; public class Demo { public static void main(String[] arg) { Thread t1 = new Thread(new MyThreadRunnable()); t1.start(); // t1.run(); } private static class MyThreadRunnable implements Runnable { @Override public void run() { if (this != currentThread()) { // 此处报错 throw new IllegalStateException("run() must not be called directly"); } Thread thread = currentThread(); System.out.println(thread.getName() + " run started..."); for (int i = 1; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { System.out.println(e.getMessage()); } } System.out.println('\n' + thread.getName() + " run ended."); } } }
行为差异的原因
核心在于this的指向和currentThread()返回对象的本质区别:
继承Thread类的场景:
MyThread是Thread的子类,它本身就是一个线程实例。当调用a.start()后,JVM启动新线程并执行run(),此时this就是当前线程对象(currentThread()返回的就是这个MyThread实例),所以this == currentThread()成立,不会抛出异常;而直接调用a.run()时,代码在main线程执行,currentThread()返回main线程实例,this是MyThread实例,两者不相等,触发异常,符合预期。实现Runnable接口的场景:
MyThreadRunnable只是一个任务载体,并非Thread实例。当创建new Thread(new MyThreadRunnable())时,Thread对象t1才是真正的线程实例。调用t1.start()后,新线程执行run()方法时,this指向的是MyThreadRunnable的实例,而currentThread()返回的是Thread对象t1——这是两个完全不同的对象,所以this != currentThread()永远成立,直接抛出异常。
遗漏的核心要点
- Runnable是任务抽象,不是线程本身:实现Runnable的类仅定义了线程要执行的逻辑,它不是Thread对象,不能与线程实例划等号。
this与currentThread()的指向逻辑不同:this指向当前代码所属的对象,currentThread()返回的是正在执行当前代码的Thread实例。只有当对象本身是Thread子类时,两者才会指向同一个实例。
修正方案(针对Runnable场景)
如果要实现“禁止直接调用run()”的判断,可以保存对应的Thread实例并对比:
import static java.lang.Thread.currentThread; public class Demo { public static void main(String[] arg) { MyThreadRunnable runnable = new MyThreadRunnable(); Thread t1 = new Thread(runnable); runnable.bindThread(t1); t1.start(); // 直接调用run会触发异常:runnable.run(); } private static class MyThreadRunnable implements Runnable { private Thread boundThread; public void bindThread(Thread thread) { this.boundThread = thread; } @Override public void run() { if (currentThread() != boundThread) { throw new IllegalStateException("run() must not be called directly"); } Thread current = currentThread(); System.out.println(current.getName() + " run started..."); for (int i = 1; i < 100; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { System.out.println(e.getMessage()); } } System.out.println('\n' + current.getName() + " run ended."); } } }
内容的提问来源于stack exchange,提问作者A m
相关产品推荐
相关产品推荐

