当我们拥有currentThread()方法时,为什么Thread类具有静态方法?

斯特凡

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请进行大量检查。

那就是“中断”系统出现的地方。这个想法是:

  1. 要中断任何线程,请使用以下命令提高其中断标志: thatThread.interrupt();

  2. 所有执行可中断操作的方法都应检查此标志。过程是:如果引发该异常,则[A]清除它,然后[B]处理中断,执行程序员打算在中断时发生的任何事情(只需停止运行,或重新检查某些条件,重新读取一些配置文件,谁知道-它是编程,无论您想要什么。如果可以处理中止某些操作的概念,但不能处理它,则清除该标志并抛出InterruptedException,以便调用者可以处理它。

  3. 结果,任何知道“我被打扰了!”的代码。意味着应同时检查该标志(尤其是该代码是否具有事件循环(大多数基于线程的代码确实具有此事件循环)),并从指定用于抛出该异常的任何方法中捕获InterruptedException,并以完全相同的方式对捕获该异常或有Thread.interrupted()返回true。

如果您处理了中断标志已启动但又不降低中断标志这一事实,那么事情就会出错。例如,如果您中止CPU绑定的比特币挖掘或其他操作,而只是在返回标志的同时返回到调用方,则下次调用方调用Thread.sleep时,thread.sleep将注意到该标志已启动并且立即退出,根本不睡觉(具体来说,通过抛出InterruptedException退出)。那不是故意的。因此,如果您对中断做出响应,则降低该标志的原因很重要。

因此,让我们回到API设计。有两种策略:

假设设计A

while (!Thread.currentThread().isInterrupted()) {
    mineAnotherBitCoin();
}
Thread.currentThread().clearInterruptFlag();

设计B

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

当我们在方法类中拥有私有属性时,为什么要使用final作为修饰符

当我们已经具有MVC提供的默认功能时,为什么我们需要Ajax / jQuery调用colntroller方法?

当您有静态块时,为什么我们需要main方法

当我们真正拥有move构造函数时,是否具有(N)RVO?

当我们有包装器类时,为什么要支持原语?

为什么我们允许在Java中拥有最终的main方法?

为什么我们在Hybris WCMS页面中已经具有ContentSlot时拥有ContentSlotName?

当我们拥有图形卡时,多核CPU的目的是什么?

为什么我们不能用私有扩展类方法覆盖基类方法?

当我们对所有人都使用存储库保存方法时,具有PATCH,POST,PUT类型有什么意义?

当我有一个私有id字段时,为什么Hibernate要求我们实现equals / hashcode方法?

当我们要私有继承基类时,为什么要进行名称公开?

当我们已经拥有重锁时,再次锁定重入锁有什么帮助?

当我们有一个红色区域时,为什么我们需要堆栈分配?

当我们拥有数值和分类数据时,哪种算法可用于聚类问题?

当我们不使用方法隐藏时,为什么不调用父方法?

为什么我们有==运算符时使用equals()方法?

当我们在类中定义委托时,有什么区别呢?

当我尝试覆盖静态方法时,为什么编译器没有抱怨?

当我们使用QString打印时,为什么会有双引号?

当我们有IDistributedCache时,为什么要使用IMemoryCache?

当我们已经有了“ apt-get”时,为什么要制作“ apt”?

当我们有组件时,为什么还需要服务?

为什么我们不能在扩展类的静态方法中使用此实例?

为什么当我们调用静态最终变量时不首先执行静态块

当我们想向 DOM 添加方法时,为什么要将 elment 存储在变量中?

为什么在带有ehcache的春季我们不能将@Cacheable与静态方法一起使用?

当我们只有一个通用特征时,Rust 处理常量数学的方法是什么

Data Vault 2.0-为什么在拥有信息市场时我们需要业务保险库?