Thread
类有许多由类名调用的静态方法。他们之中有一些是:
但是,我们提供了currentThread()
返回当前正在执行的线程对象的方法。一些是:
不幸的是,这引起了我的困惑。当我想到自己想要的方法时,我不知道该将其视为static还是instance。那么为什么他们要采用这两种方法呢?
我的意思是,难道不能将它们全部归为同一“通话”吗?例如,为什么用sleep()
static而不用调用实例方法Thread.currentThread().sleep()
?另一个奇怪的例子是在之间,interrupted()
并且isInterrupted()
以不同的方式定义。他们做的完全一样,只是interrupted()
另外清除了中断标志。有谁对此有逻辑的答案,所以我在哪里找到每种方法都毫不费力?
这很棘手; 每种方法的答案都不同。让我们浏览一下您所命名的:
想象一下我叫:someOtherThread.sleep(1000L);
。这是什么意思?当然,这应该意味着:休眠其他线程,而不是我的线程。除非Java不能提供这些功能:您可以休眠自己的线程,但不能随意告诉其他线程冻结,就像他们在执行mime动作,执行任意命令的中间一样。例如,如果该线程当前处于阻塞状态,例如,等待操作系统从读取的文件中提供一些字节,那肯定不能只是睡着了,在很多其他情况下,线程无法做到这一点。
因此,java不提供此功能-您无法使其他线程休眠。只有你自己的。在API设计中,至少有两种方法可以使这一点变得清楚:
首先是让sleep作为实例方法(因此,您必须编写eg Thread.currentThread().sleep(1000L);
),并指定将保证的方法始终(IllegalStateException
如果您在除自己线程之外的任何线程上调用它)立即抛出一个。这意味着只能在运行时捕获编译/写入时可检测到的错误情况(这很糟糕;尽早发现问题要比晚捕获更好),这使您必须编写的代码不必要地睡得更长一些,可以在线程实例上调用的sleep方法的存在肯定表明您可以休眠其他线程。这只是糟糕的API设计。
第二是使睡眠静止。
可以这样考虑:java.lang.Thread
是两个基本不相关的方法批次的容器:一个是可以在线程上使用的一组方法(那些是实例方法)。另一个是一堆与线程和流相关的原语,例如“睡眠”,“产量”和中断交互。他们恰好被推到同一个阶级。
这可能是最棘手的。与睡眠不同,实际上您可以询问另一个线程的中断标志状态。
之所以有两种方法,是因为中断系统或多或少打算使用API设计。
中断系统的设计如下:
如果您希望某个线程由于某种未指定的原因而停止其正在执行的操作(例如,您希望其重新检查某些条件,或者只是停止运行,或者可以想到的其他任何方法),则需要一种机制来发出信号。特别是,您需要一种机制来确保任何可中断的阻塞操作(例如Thread.sleep(100000L)
被中断)。换句话说,您不能只说:无论如何,这取决于代码本身,只是,AtomicBoolean
请进行大量检查。
那就是“中断”系统出现的地方。这个想法是:
要中断任何线程,请使用以下命令提高其中断标志: thatThread.interrupt();
所有执行可中断操作的方法都应检查此标志。过程是:如果引发该异常,则[A]清除它,然后[B]处理中断,执行程序员打算在中断时发生的任何事情(只需停止运行,或重新检查某些条件,重新读取一些配置文件,谁知道-它是编程,无论您想要什么。如果可以处理中止某些操作的概念,但不能处理它,则清除该标志并抛出InterruptedException,以便调用者可以处理它。
结果,任何知道“我被打扰了!”的代码。意味着应同时检查该标志(尤其是该代码是否具有事件循环(大多数基于线程的代码确实具有此事件循环)),并从指定用于抛出该异常的任何方法中捕获InterruptedException,并以完全相同的方式对捕获该异常或有Thread.interrupted()
返回true。
如果您处理了中断标志已启动但又不降低中断标志这一事实,那么事情就会出错。例如,如果您中止CPU绑定的比特币挖掘或其他操作,而只是在返回标志的同时返回到调用方,则下次调用方调用Thread.sleep时,thread.sleep将注意到该标志已启动并且立即退出,根本不睡觉(具体来说,通过抛出InterruptedException退出)。那不是故意的。因此,如果您对中断做出响应,则降低该标志的原因很重要。
因此,让我们回到API设计。有两种策略:
while (!Thread.currentThread().isInterrupted()) {
mineAnotherBitCoin();
}
Thread.currentThread().clearInterruptFlag();
while (!Thread.checkAndClearInterruptFlag()) {
mineAnotherBitCoin();
}
请注意,设计B在概念上要短得多,在检查标志和清除标志之间没有“缝隙”,因此从根本上讲,它不易出错。此外,出于某种原因,已经决定提高中断标志是您可以对其他线程执行的操作(毕竟,中断自己是没有意义的),但是清除一个是您只能对自己执行的操作线。
B是Java实际拥有的,除了方法的名称有些奇怪interrupted()
,而不是checkAndClearInterruptFlag()
。如果您想解释一下为什么Java中的某些方法被命名为可疑名称的原因,那是因为Java不喜欢破坏向后兼容性。
从根本上说的话,而他们真正的声音相似,isInterrupted()
并且interrupted()
做了两个非常不同的事情。
isInterrupted()
是要检查某个线程是否已经被中断,并且它对该中断的响应仍未决(尚未处理)。
interrupted()
是您在while循环中放入条件的内容,该循环定义了线程实现的核心主体(您的“事件循环”)。
*)绝大多数关于如何在Java中创建线程的示例都是错误的,因为它们没有正确执行此操作,这无济于事。他们往往是while (true)
或while (!running) {}
或类似,无论是忽略中断或完全用手卷中断式的“跑步”的概念。
足够简单:如果它是一个概念上不属于任何特定线程的事物(例如“现在有多少个线程处于活动状态”),或者它是一个实用程序概念(例如“ sleep”),或者是一个事物从VM设计原则出发,只能对自己的线程执行操作,而对其他任何操作都不能执行,那么这是Thread中的静态方法。
如果它确实属于某个特定线程,并且VM允许您将其用于其他线程(例如中断它,询问其名称,ID或优先级,获取堆栈转储,冻结该线程直至另一个线程)完成或设置其优先级),则它是一个实例方法。
您可以通过许多方式来逆转此逻辑:如果您想做一些与线程相关的业务,请在Thread类中检查似乎可以描述所需内容的内容。然后检查该方法是否是静态的。如果它是静态的,则不会对其他任何线程执行此操作(例如清除中断标志或休眠)。如果是实例,则可以对其他线程执行此操作(例如更改其优先级)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句