Java线程最鲜为人知的事实和用例是什么?

有些人喜欢爬山,有些人喜欢跳伞。 我,我喜欢Java。 我喜欢它的一件事是,您永不停止学习。 您每天使用的工具通常可以为您带来全新的面貌,以及您还没有机会看到的方法和有趣的用例。 例如线程。 实际线程。 或者更好的是,Thread类本身。 当我们使用高可伸缩性系统时,并发编程永远不会停止挑战,但是现在我们将讨论一些不同的东西。

在这篇文章中,您将看到线程支持的一些鲜为人知但有用的技术和方法。 无论您是初学者,高级用户还是专家Java开发人员,都请尝试查看其中哪些已为您所知,以及哪些是新产品。 关于线程,您还有其他值得一提的地方吗? 我希望在下面的评论中听到它。 让我们开始吧。

初学者

1.线程名称

应用中的每个线程都有一个名称,即构造该线程时为其生成的简单Java字符串。 默认名称值从“ Thread-0”到“ Thread-1”,“ Thread-2”,依此类推。 现在出现了更有趣的部分–线程公开了两种可用来设置其名称的方法:

1.线程构造函数,这是最简单的一个:

class SuchThread extends Thread {Public void run() {System.out.println ("Hi Mom! " + getName());}}SuchThread wow = new SuchThread("much-name");

2.线程名称设置器:

wow.setName(“Just another thread name”);

是的,线程名是可变的。 因此,除了在实例化它们时设置自定义名称外,我们还可以在运行时更改它。 名称字段本身设置为简单的String对象。 这意味着它最多可以包含2³¹-1个字符(Integer.MAX_VALUE)。 我说的绰绰有余。 请注意,该名称不像唯一ID,因此线程可以共享相同的名称。 另外,不要尝试将null作为名称传递,除非您希望引发异常(不过“ null”是可以的,我没有判断!)。

使用线程名称进行调试

因此,既然您已经可以访问线程名,那么遵循自己的一些命名约定可以在发生问题时使您的生活变得更加轻松。 “ Thread-6”听起来有些无情,我相信您可以想到一个更好的名字。 在处理用户请求时,将其与自分配的事务ID结合在一起,将其附加到线程的名称上,您将大大减少错误解决时间。

保留在此处的一个好习惯是确保您在应用程序的每个线程的入口点生成一个UUID,并在请求在节点,进程和线程之间传递时保持一致。 让我们看一下这个示例,某个线程池中的一个工作线程挂起了太长时间。 您运行jstack仔细看一下,然后看到以下内容:

“pool-1-thread-1″ #17 prio=5 os_prio=31 tid=0x00007f9d620c9800
nid=0x6d03 in Object.wait() [0x000000013ebcc000]

好的,“ pool-1-thread-1”,为什么这么严重? 让我们更好地了解您,并想出一个更合适的名称:

Thread.currentThread().setName(Context + TID + Params + current Time, ...);

现在,当我们再次运行jstack时,情况看起来好多了:

”Queue Processing Thread, MessageID: AB5CAD, type:
AnalyzeGraph, queue: ACTIVE_PROD, Transaction_ID: 5678956,
Start Time: 30/12/2014 17:37″ #17 prio=5 os_prio=31 tid=0x00007f9d620c9800
nid=0x6d03 in Object.wait() [0x000000013ebcc000]

我们知道线程在阻塞时正在做什么,并且还拥有启动所有线程的事务ID。 您可以追溯步骤,重现错误,隔离并解决问题。 要了解更多有关使用jstack的酷方法的信息,您可以在这里查看这篇文章。

2.线程优先级

优先级是另一个有趣的领域线程。 线程的优先级是介于1(MIN_PRIORITY)到10(MAX_PRIORITY)之间的值,主线程的默认值为5(NORM_PRIORITY)。 每个新线程都获得其父级的优先级,因此,如果您不手动使用它,则您所有线程的优先级都可能设置为5。这也是Thread类的一个经常被忽略的字段,我们可以访问和操作它。通过方法getPriority()setPriority() 。 无法在线程构造函数中进行设置。

谁仍然需要优先考虑?

当然,并非所有线程都是平等创建的,有些线程需要您的CPU立即关注,而其他线程只是后台任务。 优先级用于向OS线程调度程序发出信号。 在Takipi,我们开发了一个错误跟踪和分析工具,为用户处理新异常的线程将获得MAX_PRIORITY,而处理诸如报告新部署等任务的线程将获得较低的优先级。 可能希望具有更高优先级的线程从与JVM一起使用的线程调度程序中获得更多时间。 好吧,并非总是如此。

每个Java线程都会在OS级别上打开一个新的本机线程,并且您为每个平台以不同的方式将您设置的Java优先级转换为本机优先级。 在Linux上,在运行应用程序时,还必须包括“ -XX:+ UseThreadPriorities”标志,以将其考虑在内。 话虽如此,线程优先级仍然只是您提供的建议。 与本机Linux优先级相比,它们甚至没有涵盖整个值范围(1..99,以及线程范围的影响范围在-20..20之间)。 主要要点是保持自己的逻辑以确保优先级在每个线程获得的CPU时间中得到反映的重要性,但不建议仅依赖优先级。

高级

3.线程本地存储

这与我们在这里谈论的其他生物有些不同。 ThreadLocal是一个从Thread类( java.lang.ThreadLocal )实现的概念,但是为每个线程存储唯一的数据。 就像上面说的那样,它为您提供了线程本地存储,这意味着您可以创建每个线程实例唯一的变量。 与您拥有线程名称或优先级的方式类似,您可以创建自定义字段,使其看起来像是Thread类的成员。 那不是很酷吗? 但是,我们不要太激动 ,前面有一些警告。

建议使用以下两种方法之一创建ThreadLocal:作为静态变量或单例的一部分,在该变量中不必是静态的。 请注意,它位于全局范围内,但对每个能够访问它的线程都作用于本地。 这是一个ThreadLocal变量的示例,该变量持有我们自己的数据结构以便于访问:

public static class CriticalData
{public int transactionId;public int username;
}public static final ThreadLocal<CriticalData> globalData =new ThreadLocal<CriticalData>();

一旦有了ThreadLocal,就可以使用globalData.set()globalData.get()对其进行访问

全球? 一定是邪恶的

不必要。 ThreadLocal变量可以保留事务ID。 当您有一个未捕获的异常使您的代码冒泡时,这可以派上用场。 一个好的做法是设置一个UncaughtExceptionHandler ,我们也可以通过Thread类获得它,但必须自己实现。 一旦我们到达那个阶段,关于实际上是什么使我们到达那里的提示就不多了。 我们剩下的是Thread对象,当堆栈框架关闭时,无法访问将我们带到那里的任何变量。 在我们的UncaughtExceptionHandler中,随着线程的最后呼吸,ThreadLocal几乎是我们剩下的仅有的事情之一。

我们可以本着以下精神做一些事情:

System.err.println("Transaction ID " + globalData.get().transactionId);

就像这样,我们为错误添加了一些有价值的上下文。 使用ThreadLocal的一种更有创意的方法是通过分配指定的内存块,以供工作线程反复使用作为缓冲区。 当然,这可能会很有用,具体取决于您在内存的哪一侧与CPU开销之间的权衡。 也就是说,要注意的是滥用我们的内存空间。 只要特定的线程处于活动状态,它就存在于特定线程中,除非将其释放或线程死亡,否则不会被垃圾回收。 因此,在使用它时最好小心并保持简单。

4.用户线程和守护程序线程

回到我们的线程类。 我们应用中的每个线程都会收到“用户”或“守护程序”状态。 换句话说,前景或后台线程。 默认情况下,主线程是用户线程,每个新线程都获得创建它的线程的状态。 因此,如果将线程设置为守护程序,则它创建的所有线程也将被标记为守护程序。 当您的应用程序中剩下的仅处于运行状态的线程处于守护程序状态时,该过程将关闭。 要进行测试,检查和更改线程状态,我们有布尔值.setDaemon(true).isDaemon()方法。

您何时设置Daemon线程?

当线程对线程的结束不是很关键时,应将其状态更改为守护进程,以便进程可以关闭。 它消除了正确关闭线程,立即停止所有操作的麻烦,让我们Swift结束了它。 另一方面,当有一个线程运行的操作必须正确结束时,否则将发生不良情况,请确保将其设置为用户线程。 关键事务可以是例如数据库条目或完成不间断的更新。

专家

5. Java处理器亲和力

这部分使我们更接近代码与金属相遇的硬件。 处理器关联允许您将线程或进程绑定到特定的CPU内核。 这意味着无论何时执行该特定线程,它都将专门在一个特定内核上运行。 通常情况下,操作系统线程调度程序将根据其自己的逻辑担当此角色,可能会考虑我们前面提到的线程优先级。

讨价还价的筹码是CPU缓存。 如果一个线程只在一个特定的内核上运行,则更有可能享受将所有数据准备好在缓存上的乐趣。 当数据已经存在时,无需重新加载它。 您节省的微秒数可以被更好地利用,并且代码实际上将在该时间运行,从而更好地利用分配的CPU时间。 尽管确实在操作系统级别进行了一些优化,并且硬件体系结构当然也起着重要作用,但是使用亲和力可以消除线程切换内核的机会。

由于这里有许多因素在起作用,因此确定处理器亲和力将如何影响您的吞吐量的最佳方法是接受测试的习惯。 尽管可能并不总是会好得多,但是您可能会遇到的好处之一就是吞吐量稳定。 亲和力策略可以降低到手术水平,具体取决于获得的收益。 高频交易行业将是这类事情最重要的地方之一。

测试处理器亲和力

Java没有对处理器相似性的本机支持,但这当然还没有结束。 在Linux上,我们可以使用tasket命令设置进程亲和力。 假设我们正在运行一个Java进程,并且希望将其固定到特定的CPU:

taskset -c 1 “java AboutToBePinned”

或者,如果它已经在运行:

taskset -c 1 <PID>

现在,要进入线程级别,我们需要插入一些新代码。 幸运的是,有一个开源库可以帮助我们做到这一点: Java-Thread-Affinity 。 由OpenHFT的Peter Lawrey撰写,这可能是最简单的方法。 让我们看一个固定线程的简单例子,更多的信息可以在该库的GitHub存储库中找到:

AffinityLock al = AffinityLock.acquireLock();

就是这样。 GitHub上提供了用于获取锁的更高级选项,其中考虑了选择特定内核的不同策略。

结论

我们已经看到了5种查看线程的方法:线程名称,线程本地存储,优先级,守护程序线程和相似性。 希望这对您每天处理的事情有所帮助,并很高兴听到您的评论! 还有哪些其他线程处理方法可以适用?

翻译自: https://www.javacodegeeks.com/2015/01/thread-magic-tricks-5-things-you-never-knew-you-can-do-with-java-threads.html

线程魔术技巧:使用Java线程可以做的5件事相关推荐

  1. 线程魔术技巧:Java线程可以做的5件事

    Java线程最鲜为人知的事实和用例是什么? 有些人喜欢爬山,有些人喜欢跳伞. 我,我喜欢Java. 我喜欢它的一件事是,您永不停止学习. 您每天使用的工具通常可以向您展示全新的方面,以及您还没有机会看 ...

  2. 开发测试矛盾java吧_不愿看到Java开发者再做的10件事

    5.用Calendar或Date来做日期计算 用JDK中的Date和Calendar来做复杂的日期和时间计算简直就是浪费生命.内建的类仅仅支持最基本的操作,而且一点也不直观.我们还是用JODA Tim ...

  3. 不愿看到Java开发者再做的10件事

    编者注:Andy是OSI(开发系统集成者)的CEO,同时也是位思想先锋及优秀博客作者. William F. Buckley.Jr 曾经说过,"保守主义者是那些逆着历史潮流不断喊停的人,其他 ...

  4. java10没人开发了吗,不愿看到Java开发者再做的10件事

    Tt!}V8_y0编者注:Andy是OSI(开发系统集成者)的CEO,同时也是位思想先锋及优秀博客作者.VMW9_&etR0 !^/fy;@"s0William F. Buckley ...

  5. java runnable wait_面试官:都说阻塞 I/O 模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?...

    摘要: 原创出处 https://studyidea.cn 「公众号:程序通事 」欢迎关注和转载,保留摘要,谢谢! 使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而 ...

  6. new thread后会阻塞主程序吗_阻塞模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?...

    使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而让出 CPU 的执行权,直到数据读取完成.这个期间如果使用 jstack 查看线程状态,却可以发现Java 线程状态 ...

  7. 既然阻塞 I/O 会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?

    使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而让出 CPU 的执行权,直到数据读取完成.这个期间如果使用 jstack 查看线程状态,却可以发现Java 线程状态 ...

  8. 热点和秒杀来临前要做的5件事

    记得当年<甄嬛传>热播,调用了我们团队的媒体资讯接口.接口被调用挂了.当时虽然我不负责那一块,只是目睹了当时大家在临场解决问题的紧张一幕.但是这件事在我心里埋下了种子,从此追求高可用.高稳 ...

  9. 安装Ubuntu后必须要做的几件事 一 --基础应用篇

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 2017 ...

  10. Java中有关Null的9件事

    对于Java程序员来说,null是令人头痛的东西.时常会受到空指针异常(NPE)的骚扰.连Java的发明者都承认这是他的一项巨大失误.Java为什么要保留null呢?null出现有一段时间了,并且我认 ...

最新文章

  1. Spark1.0.0 开发环境高速搭建
  2. InsightFace笔记
  3. Dubbo3.0|阿里巴巴服务框架三位一体的选择与实践
  4. 12小时紧急策划 复盘一篇10W+的诞生全历程
  5. Codeforces - 466C - Number of Ways - 组合数学
  6. wxWidgets:wxInitDialogEvent类用法
  7. mysql bench建立一张表_使用MySQL Workbench建立数据库,建立新的表,向表中添加数据...
  8. 如何用50行代码构建情感分类器
  9. param.requires_grad = False的作用
  10. Oracle笔记:备份还原
  11. .Net Core 中间件之主机地址过滤(HostFiltering)源码解析
  12. 多行文本溢出显示省略号(…) text-overflow: ellipsis
  13. think in java 读书笔记 2 —— 套接字
  14. value数字 vue_Vue数字输入框组件使用方法详解
  15. win10无法装载iso文件_win10系统解决方案无法打开iso文件
  16. 【效率】7个免费的PDF文献资源网站,再也不用为搜索文献发愁了!
  17. 主流PHP博客系统比较
  18. html字体字号颜色怎么设置,html字体样式大全 html怎么改变字体大小和颜色
  19. c语言关键字和运算符,C语言关键字和运算符.doc
  20. 赴美生子的一些调研——诚信是拒签之本,中国的月子中心在美是非法的,医疗和教育费用高...

热门文章

  1. jzoj4804-[NOIP2016提高A组模拟9.28]成绩调研【指针,模拟】
  2. 【并查集】打击犯罪(ssl 2342)
  3. [XSY3383]多线程(笛卡尔树,DP)
  4. SpringBoot集成Flowable
  5. JavaFX图表(一)
  6. 当你「ping 一下」的时候,你知道它背后的逻辑吗
  7. JVM-对象的存活与死亡
  8. 解析HTTP协议六种请求方法,get,head,put,delete,post有什么区别
  9. Spring Boot面试题
  10. epoll 浅析以及 nio 中的 Selector