为什么当我们有 currentThread() 方法时 Thread class 有静态方法?
Why does Thread class has static methods when we have currentThread() method?
Thread
class 有许多由 class 名称调用的静态方法。他们之中有一些是:
但是,我们提供了方法 currentThread()
,returns 当前正在执行线程对象。一些是:
不幸的是,这在我脑海中造成了混乱。当我想到我想要的方法时,我不知道我会发现它是 static 还是 instance。那么他们为什么要采用这两种方法呢?
我的意思是,他们不能都归为同一个 'calling' 吗?例如,为什么 sleep()
static 而不是 instance 方法用 Thread.currentThread().sleep()
调用?另一个奇怪的例子是以不同方式定义的 interrupted()
和 isInterrupted()
之间。他们做完全一样的事情,只是 interrupted()
额外清除中断标志。有没有人对此有合理的答案,所以我很容易在哪里找到每种方法?
因为您不能让不是您所在线程的另一个线程休眠。即使你调用Thread.currentThread().sleep()
,你也是在调用静态方法'sleep'。如果您要在不同的 Thread
对象上调用 sleep
方法,它仍然会使当前线程休眠。
如果你想让一个不同的线程休眠,你应该设置一个标志让另一个线程读取,这会导致它休眠。
这很棘手;每种方法的答案都不同。让我们来看看你命名的那些:
Thread.sleep
假设我调用了:someOtherThread.sleep(1000L);
。这意味着什么?这当然应该意味着:休眠另一个线程,而不是我的线程。除了那不是 java 提供的东西:你可以休眠你自己的线程,但你不能任意地告诉其他线程冻结,就像他们在做一个哑剧一样,在执行一些任意命令的过程中。例如,如果该线程当前被阻塞,比如说,等待 OS 从文件读取中传送一些字节,那绝对不能只是睡着了,还有很多很多其他线程不能做的场景那。
因此,java 不提供此功能 - 您无法休眠其他线程。只有你自己的。在 API 设计中有两种不同的方法可以使这一点至少在一定程度上清楚:
首先是让 sleep 成为一个实例方法(因此,您必须编写例如 Thread.currentThread().sleep(1000L);
),并指定它将保证始终立即抛出 IllegalStateException
如果您在除您自己的线程之外的任何线程上调用它。这意味着 compile/write-time 可检测到的错误条件只会在运行时被捕获(这很糟糕;较早发现问题显然比稍后发现问题要好),它使您必须编写的代码不必要地更长地休眠,以及可以在线程实例上调用的睡眠方法的存在肯定 建议 您可以睡眠其他线程。这只是糟糕的 API 设计。
二是让睡眠静止。
这样想:java.lang.Thread
是两个几乎不相关的方法批次的容器:一个是一组可以在线程上使用的方法(那些是实例方法)。另一个是一堆线程和流相关的原语,比如'sleep'、'yield'、中断交互。他们只是碰巧被推到同一个 class.
中断
这可能是最棘手的。与休眠不同,您 可以 实际上询问另一个线程的中断标志状态。
有两种方法的原因或多或少是因为中断系统的API设计。
中断系统设计如下:
如果你想让一些线程因为一些未指明的原因停止它正在做的事情(例如,你想让它达到re-check某种条件,或者只是停止运行,或者任何你能想想)那么你需要一种机制来发出这个信号。特别是,您需要这样一种机制来确保任何可中断的阻塞操作(例如 Thread.sleep(100000L)
)都被中断。换句话说,你不能只是说:不管怎样,这取决于代码本身,只是,嗯,做一个 AtomicBoolean
并经常检查它。
这就是 'interrupt' 系统的用武之地。想法是:
要中断任何线程,提升其中断标志,thatThread.interrupt();
所有执行可中断操作的方法都应该检查这个标志。程序是:如果它被引发,然后 [A] 清除它,并且 [B] 处理中断,做任何程序员打算在中断时发生的事情(只是停止 运行,或 re-check 一些条件, re-read 一些配置文件,谁知道 - 它是编程,无论你想要什么意思)。如果您可以处理中止某些操作的概念,但您不能处理它,那么清除该标志并抛出 InterruptedException,以便调用者可以处理它。
因此,任何知道 'I was interrupted!' 意味着什么的代码都应该检查标志(特别是如果该代码有一个事件循环,大多数 thread-based 代码确实有), 并从指定抛出它的任何方法中捕获 InterruptedException,并以完全相同的方式做出反应以捕获该异常或使 Thread.interrupted()
return 为真。
如果您处理中断标志已启动但未降低它的事实,事情就会变得很糟糕。例如,如果您中止了您的 CPU-bound 比特币挖掘或诸如此类的事情,并且只是 return 返回给您的调用者同时留下标志,那么下次调用者调用 Thread.sleep、thread.sleep会注意到标志已升起并立即退出,根本不睡觉(具体来说,通过抛出 InterruptedException 退出)。那不是故意的。因此,为什么重要的是,如果您响应中断,则降低该标志。
所以,让我们回到API设计。有两种策略:
假设设计 A
while (!Thread.currentThread().isInterrupted()) {
mineAnotherBitCoin();
}
Thread.currentThread().clearInterruptFlag();
设计 B
while (!Thread.checkAndClearInterruptFlag()) {
mineAnotherBitCoin();
}
请注意设计 B 在概念上是如何短得多的,在检查标志和清除标志之间没有 'gap',因此从根本上不容易出错。此外,出于某些原因,已经决定提高中断标志是您可以对其他线程执行的操作(毕竟没有必要中断您自己),但是清除中断标志是您只能对自己执行的操作线程。
B 是 java 实际拥有的,只是方法有点奇怪只是命名为 interrupted()
,而不是 checkAndClearInterruptFlag()
。如果您想解释为什么 java 中的某些方法的命名有些可疑,那是因为 java 不喜欢破坏向后兼容性。
从根本上说,虽然它们听起来很相似,但 isInterrupted()
和 interrupted()
做了两件截然不同的事情。
isInterrupted()
是检查某个线程是否已经被中断并且它对这个中断的响应还在pending(还没有处理它)。
interrupted()
是您在 while 循环中放入的条件,它定义线程实现的核心主体(您的 'event loop')。
*) java 中关于如何创建线程的绝大多数示例都是错误的,因为它们没有正确执行此操作,这无济于事。它们往往是 while (true)
或 while (!running) {}
或类似的,要么完全忽略中断,要么使用手动 interrupt-esque 'running' 概念。
那么我怎么知道去哪里看?
足够简单:如果它是概念上不属于任何特定线程的东西(例如'how many threads are active right now'),或它是一个实用概念(例如as 'sleep'), or 是VM设计原则上只能对自己线程做的事情,不能对其他任何事情做,那么就是静态方法线程。
如果它确实属于某个特定线程并且 VM 允许您对其他线程执行此操作(例如中断它、询问它的名称、ID 或优先级、获取堆栈转储、冻结它线程直到另一个线程完成,或设置其优先级),那么它就是一个实例方法。
您可以通过多种方式扭转这种逻辑:如果您想做一些与线程相关的业务,请检查线程 class 以寻找似乎描述您想要的内容的内容。然后检查该方法是否是静态的。如果它是静态的,则您无法对任何其他线程执行此操作(例如清除中断标志或睡眠)。如果是实例,您可以对其他线程执行此操作(例如更改其优先级)。
Thread
class 有许多由 class 名称调用的静态方法。他们之中有一些是:
但是,我们提供了方法 currentThread()
,returns 当前正在执行线程对象。一些是:
不幸的是,这在我脑海中造成了混乱。当我想到我想要的方法时,我不知道我会发现它是 static 还是 instance。那么他们为什么要采用这两种方法呢?
我的意思是,他们不能都归为同一个 'calling' 吗?例如,为什么 sleep()
static 而不是 instance 方法用 Thread.currentThread().sleep()
调用?另一个奇怪的例子是以不同方式定义的 interrupted()
和 isInterrupted()
之间。他们做完全一样的事情,只是 interrupted()
额外清除中断标志。有没有人对此有合理的答案,所以我很容易在哪里找到每种方法?
因为您不能让不是您所在线程的另一个线程休眠。即使你调用Thread.currentThread().sleep()
,你也是在调用静态方法'sleep'。如果您要在不同的 Thread
对象上调用 sleep
方法,它仍然会使当前线程休眠。
如果你想让一个不同的线程休眠,你应该设置一个标志让另一个线程读取,这会导致它休眠。
这很棘手;每种方法的答案都不同。让我们来看看你命名的那些:
Thread.sleep
假设我调用了:someOtherThread.sleep(1000L);
。这意味着什么?这当然应该意味着:休眠另一个线程,而不是我的线程。除了那不是 java 提供的东西:你可以休眠你自己的线程,但你不能任意地告诉其他线程冻结,就像他们在做一个哑剧一样,在执行一些任意命令的过程中。例如,如果该线程当前被阻塞,比如说,等待 OS 从文件读取中传送一些字节,那绝对不能只是睡着了,还有很多很多其他线程不能做的场景那。
因此,java 不提供此功能 - 您无法休眠其他线程。只有你自己的。在 API 设计中有两种不同的方法可以使这一点至少在一定程度上清楚:
首先是让 sleep 成为一个实例方法(因此,您必须编写例如 Thread.currentThread().sleep(1000L);
),并指定它将保证始终立即抛出 IllegalStateException
如果您在除您自己的线程之外的任何线程上调用它。这意味着 compile/write-time 可检测到的错误条件只会在运行时被捕获(这很糟糕;较早发现问题显然比稍后发现问题要好),它使您必须编写的代码不必要地更长地休眠,以及可以在线程实例上调用的睡眠方法的存在肯定 建议 您可以睡眠其他线程。这只是糟糕的 API 设计。
二是让睡眠静止。
这样想:java.lang.Thread
是两个几乎不相关的方法批次的容器:一个是一组可以在线程上使用的方法(那些是实例方法)。另一个是一堆线程和流相关的原语,比如'sleep'、'yield'、中断交互。他们只是碰巧被推到同一个 class.
中断
这可能是最棘手的。与休眠不同,您 可以 实际上询问另一个线程的中断标志状态。
有两种方法的原因或多或少是因为中断系统的API设计。
中断系统设计如下:
如果你想让一些线程因为一些未指明的原因停止它正在做的事情(例如,你想让它达到re-check某种条件,或者只是停止运行,或者任何你能想想)那么你需要一种机制来发出这个信号。特别是,您需要这样一种机制来确保任何可中断的阻塞操作(例如 Thread.sleep(100000L)
)都被中断。换句话说,你不能只是说:不管怎样,这取决于代码本身,只是,嗯,做一个 AtomicBoolean
并经常检查它。
这就是 'interrupt' 系统的用武之地。想法是:
要中断任何线程,提升其中断标志,
thatThread.interrupt();
所有执行可中断操作的方法都应该检查这个标志。程序是:如果它被引发,然后 [A] 清除它,并且 [B] 处理中断,做任何程序员打算在中断时发生的事情(只是停止 运行,或 re-check 一些条件, re-read 一些配置文件,谁知道 - 它是编程,无论你想要什么意思)。如果您可以处理中止某些操作的概念,但您不能处理它,那么清除该标志并抛出 InterruptedException,以便调用者可以处理它。
因此,任何知道 'I was interrupted!' 意味着什么的代码都应该检查标志(特别是如果该代码有一个事件循环,大多数 thread-based 代码确实有), 并从指定抛出它的任何方法中捕获 InterruptedException,并以完全相同的方式做出反应以捕获该异常或使
Thread.interrupted()
return 为真。
如果您处理中断标志已启动但未降低它的事实,事情就会变得很糟糕。例如,如果您中止了您的 CPU-bound 比特币挖掘或诸如此类的事情,并且只是 return 返回给您的调用者同时留下标志,那么下次调用者调用 Thread.sleep、thread.sleep会注意到标志已升起并立即退出,根本不睡觉(具体来说,通过抛出 InterruptedException 退出)。那不是故意的。因此,为什么重要的是,如果您响应中断,则降低该标志。
所以,让我们回到API设计。有两种策略:
假设设计 A
while (!Thread.currentThread().isInterrupted()) {
mineAnotherBitCoin();
}
Thread.currentThread().clearInterruptFlag();
设计 B
while (!Thread.checkAndClearInterruptFlag()) {
mineAnotherBitCoin();
}
请注意设计 B 在概念上是如何短得多的,在检查标志和清除标志之间没有 'gap',因此从根本上不容易出错。此外,出于某些原因,已经决定提高中断标志是您可以对其他线程执行的操作(毕竟没有必要中断您自己),但是清除中断标志是您只能对自己执行的操作线程。
B 是 java 实际拥有的,只是方法有点奇怪只是命名为 interrupted()
,而不是 checkAndClearInterruptFlag()
。如果您想解释为什么 java 中的某些方法的命名有些可疑,那是因为 java 不喜欢破坏向后兼容性。
从根本上说,虽然它们听起来很相似,但 isInterrupted()
和 interrupted()
做了两件截然不同的事情。
isInterrupted()
是检查某个线程是否已经被中断并且它对这个中断的响应还在pending(还没有处理它)。
interrupted()
是您在 while 循环中放入的条件,它定义线程实现的核心主体(您的 'event loop')。
*) java 中关于如何创建线程的绝大多数示例都是错误的,因为它们没有正确执行此操作,这无济于事。它们往往是 while (true)
或 while (!running) {}
或类似的,要么完全忽略中断,要么使用手动 interrupt-esque 'running' 概念。
那么我怎么知道去哪里看?
足够简单:如果它是概念上不属于任何特定线程的东西(例如'how many threads are active right now'),或它是一个实用概念(例如as 'sleep'), or 是VM设计原则上只能对自己线程做的事情,不能对其他任何事情做,那么就是静态方法线程。
如果它确实属于某个特定线程并且 VM 允许您对其他线程执行此操作(例如中断它、询问它的名称、ID 或优先级、获取堆栈转储、冻结它线程直到另一个线程完成,或设置其优先级),那么它就是一个实例方法。
您可以通过多种方式扭转这种逻辑:如果您想做一些与线程相关的业务,请检查线程 class 以寻找似乎描述您想要的内容的内容。然后检查该方法是否是静态的。如果它是静态的,则您无法对任何其他线程执行此操作(例如清除中断标志或睡眠)。如果是实例,您可以对其他线程执行此操作(例如更改其优先级)。