Will the Thread.currentThread() method always return the same object troughout the Runnable's lifetime?

huangapple go评论70阅读模式
英文:

Will the Thread.currentThread() method always return the same object troughout the Runnable's lifetime?

问题

我一直在我的Runnable#run()方法中使用Thread#currentThread()来获取对当前正在执行的线程的引用。由于Runnable可以在执行器中并行运行多个类似的副本,并且可能持续运行一段时间,它是否总是会返回相同的线程对象,还是在Runnable的生命周期内会发生变化?

所以基本上,当我运行这种类型的Runnable一段时间时,我会遇到问题吗?

class MyRunnable implements Runnable {
  
  @Override
  public void run() {
     Thread current = Thread.currentThread();
     
     while(!current.isInterrupted()) {
        try {
          // 一些可能需要很长时间的处理...
        } catch(InterruptedException e) {
          // 一些清理操作
          current.interrupt();
        }
     }

     // 再见
  }
}
英文:

I've been using Thread#currentThread() in my Runnable#run() method to get a reference to the currently executing thread. Since the Runnable can be running for a while with multiple similar copies in parallel in an Executor, will it always return the same Thread object or can that change over the course of the the lifetime of the Runnable?

So basically, will I run into issues when I run this kind of Runnable for a while?

class MyRunnable implements Runnable {
  
  @Override
  public void run() {
     Thread current = Thread.currentThread();
     
     while(!current.isInterrupted()) {
        try {
          // some processing that can take a while...
        } catch(InterruptedException e) {
          // some cleanup
          current.interrupt();
        }
     }

     // goodbye
  }
}

答案1

得分: 5

你的问题问得不对。只要代码在同一个线程内执行,表达式 Thread.currentThread() 将会求值为同一个对象,该对象表示该线程。

但这与“Runnable 的生命周期”无关。Runnable,更准确地说,是实现可运行接口的类的实例,它是一个普通的对象,可以独立于线程使用。特别要注意的是,多个线程可能会执行同一个对象的 run() 方法:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        Thread current = Thread.currentThread();
        System.out.println(current);
    }
}

MyRunnable r = new MyRunnable();

new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-2,5,main]

然而,这并不意味着假设在特定执行中获取相同的 Thread 实例是错误的。

在你的示例代码基础上继续:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        Thread current = Thread.currentThread();
        while(!current.isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                current.interrupt();
            }
        }
        System.out.println(current + " has been interrupted, exiting");
    }
}

MyRunnable r = new MyRunnable();

Thread[] threads = { new Thread(r), new Thread(r), new Thread(r) };

for(Thread t: threads) t.start();
for(Thread t: threads) try {
    Thread.sleep(400);
    System.out.println("going to interrupt "+t);
    t.interrupt();
    t.join();
}
catch (InterruptedException ex) {
    throw new AssertionError(ex);
}

将会正确地输出:

going to interrupt Thread[Thread-0,5,main]
Thread[Thread-0,5,main] has been interrupted, exiting
going to interrupt Thread[Thread-1,5,main]
Thread[Thread-1,5,main] has been interrupted, exiting
going to interrupt Thread[Thread-2,5,main]
Thread[Thread-2,5,main] has been interrupted, exiting

因此,Thread.currentThread()线程 的生命周期内(从该线程调用时)会返回相同的对象,而不是 Runnable 的生命周期。但这恰好符合你的需求。你也可以使用以下方式:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread() + " has been interrupted, exiting");
    }
}

达到相同的效果。但请记住,第一个示例之所以有效,是因为线程已经存储在了一个 局部变量 中。如果你打算将线程存储在对象的字段中,你必须确保该对象不会被多个线程同时使用(使用共享的可变状态时,总是要小心处理多个线程之间的情况)。

英文:

You are asking the wrong question. As long as code is executed within the same thread, the expression Thread.currentThread() will evaluate to the same object, which represents that thread.

But this has nothing to do with the “Runnable’s lifetime”. The Runnable, or more precisely the instance of the class implementing runnable, is an ordinary object that can be used independently of threads. Most notably, multiple threads may execute the run() method of the same object:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        Thread current = Thread.currentThread();
        System.out.println(current);
    }
}

MyRunnable r = new MyRunnable();

new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
Thread[Thread-0,5,main]
Thread[Thread-1,5,main]
Thread[Thread-2,5,main]

This, however doesn’t imply that it was wrong to assume to get the same Thread instance for a particular execution.

To built on your example code:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        Thread current = Thread.currentThread();
        while(!current.isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                current.interrupt();
            }
        }
        System.out.println(current+" has been interrupted, exiting");
    }
}

MyRunnable r = new MyRunnable();

Thread[] threads = { new Thread(r), new Thread(r), new Thread(r) };

for(Thread t: threads) t.start();
for(Thread t: threads) try {
    Thread.sleep(400);
    System.out.println("going to interrupt "+t);
    t.interrupt();
    t.join();
}
catch (InterruptedException ex) {
    throw new AssertionError(ex);
}

will correctly print:

going to interrupt Thread[Thread-0,5,main]
Thread[Thread-0,5,main] has been interrupted, exiting
going to interrupt Thread[Thread-1,5,main]
Thread[Thread-1,5,main] has been interrupted, exiting
going to interrupt Thread[Thread-2,5,main]
Thread[Thread-2,5,main] has been interrupted, exiting

So Thread.currentThread() will return the same object throughout the threads lifetime (when being called from that thread), not the runnable`s lifetime, but that’s precisely what you want. You could also use

class MyRunnable implements Runnable {
    @Override
    public void run() {
        while(!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread()+" has been interrupted, exiting");
    }
}

to the same effect. But keep in mind that the first example works because the thread has been stored in a local variable. If you are going to store the thread into a field of the object, you have to ensure that the object is not used by multiple threads concurrently (as you always have to take care when using shared mutable state by multiple threads).

答案2

得分: 0

每个Thread都有其自己的ID,您可以调用方法getId()来获取它。然后您可以确定是否为同一Thread

来自方法getId()javadoc

返回此线程的标识符。线程ID是在创建此线程时生成的正长整数。线程ID是唯一的,并且在其生命周期内保持不变。当线程终止时,此线程ID可能会被重用。

英文:

Each Thread has its own ID and you can call method getId() to obtain it. Then you can determine if it is the same Thread.

From the javadoc of the method getId()

> Returns the identifier of this Thread. The thread ID is a positive long number generated when this thread was created. The thread ID is unique and remains unchanged during its lifetime. When a thread is terminated, this thread ID may be reused.

答案3

得分: -1

Thread.currentThread()方法是否始终会在Runnable的生命周期内返回相同的对象?

是的,Thread.currentThread()会在特定线程中的任何调用时都返回相同的引用;但是并不是在整个Runnable的生命周期内如此,而是在当前线程的生命周期内如此。

Runnable类型与Thread是独立的,您可以在没有Thread的情况下使用它。例如,如果您将Runnable实例引用存储在某个变量中,并将相同的实例传递给Thread,则退出运行线程不会导致释放该Runnable实例。

您应该注意,一旦线程通过.start()(在此之后,JVM内部调用.run())启动,就在其完成执行后重新启动线程是不合法的。通常情况下,不允许启动同一线程超过一次。

因此,每次调用Thread.currentThread()时,您将获得对当前正在执行的线程对象的引用(在其中调用此方法的线程的引用)。

英文:

> Will the Thread.currentThread() method always return the same object troughout the Runnable's lifetime?

Yes, Thread.currentThread() will return the same reference anytime you invoke it in a particular thread; however not throughout the Runnable's lifetime, but rather throughout the lifetime of the current thread.

Runnable type exists independent from the Thread, and you can use it without the latter. If you, for example, store the Runnable instance reference in some variable, and you will pass the same instance to the Thread, exiting the runner thread will not cause the deallocation of that instance of the Runnable.

You should note, that once the thread kicks off with .start()(after which, JVM internally calls .run()), it is illegal to restart the thread after it completes execution. Generally, it is never legal to start the same thread more than once.

So, every time you call Thread.currentThread(), you will obtain the reference to the currently executing thread object (reference to the thread, in which, this method is invoked).

huangapple
  • 本文由 发表于 2020年9月24日 22:35:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/64048741.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定