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

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开销之间的权衡。 也就是说,要注意的是滥用我们的内存空间。 只要特定线程存在,ThreadLocal就存在于特定线程中,除非将其释放或线程死亡,否则不会被垃圾回收。 因此,在使用它时最好小心并保持简单。

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

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

什么时候设置守护进程线程?

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

专家

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361117.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

强制删除tfs未迁入项的两个方法。

方法1&#xff1a; 打开Vs2008的命令提示&#xff1a; 查看用户的工作区&#xff1a; 输入&#xff1a; Tf workspaces /owner:所有者或* /server:服务器名称或IP ex: tf workspaces /owner:stcct(所有者) /server:203.156.1.100(Ip地址) 删除用户的未迁入项&#xff1a; 输…

点击左侧跳到右侧

效果图 JS部分 function moveOption(e1, e2){ try{ for(var i0;i<e1.options.length;i ){ if(e1.options[i].selected){ var e e1.options[i]; e2.options.add(new Option(e.text, e.value)); e1.remove(i); iii-1 } } } catch(e){}} HTML以及CSS部分 <for…

IDC关于使用JBoss Fuse的商业价值的报告(与Apache Camel一起使用)

这只是一篇博客文章&#xff0c;具有更多的商业性质&#xff0c;但是您不能一无所有。 实际上&#xff0c;这也是使Apache Camel保持活力并保持良好状态的原因&#xff0c;这还归功于其商业上的成功。 希望从JBoss Fuse之类的产品中寻找有关在商业上使用Apache Camel的附加值的…

Spring-Quartz (一)

摘自&#xff1a; http://www.blogjava.net/Jay2009/archive/2009/03/25/259176.htmlSpring为创建Quartz的Scheduler、Trigger和JobDetail提供了便利的FactoryBean类&#xff0c;以便能够在Spring 容器中享受注入的好处。此外Spring还提供了一些便利工具类直接将Spring中的Bean…

在Java EE 7上骑骆驼–带有Swagger文档的REST服务

骆驼开箱即用。 Swagger集成就是其中之一。 不幸的是&#xff0c;大多数已经存在的功能都严重依赖于Spring。 但这并不能阻止我们在普通的Java EE 7应用程序中使用它们&#xff0c;因为有时它只是服务器的轻量级变体。 但我不想再对此进行讨论。 相反&#xff0c;我认为在所有情…

怎么隐藏滚动条又能滚动

1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>滚动条隐藏</title>6 <style>7 body, ul, li {8 margin: 0;9 padding: 0; 10 …

Eclipse to android

JDK Eclipse Android SDK ADT 1 必须软件 Java JDK SE 1.6 (jdk-7u9-windows-i586.exe) Eclipse (Eclipse IDE for Java Developers) Google Android SDK (android-sdk_r15-windows.zip) ADT (ADT-15.0.0.zip) 如果找不到可参考&#xff1a; http://blog.csdn.net/zhenyong…

canvas画饼图

<style> body { background: black; text-align: center; } #cans { background: white; } </style> <script> function disToRad(n){//将度数表示弧度计算的方法 return n*Math.PI/180;//π用PI表示&#xff0c;π180&#xff0c;所以1PI/180 } w…

Web设计趋势分析

本文译自网站设计公司weavora.com&#xff0c;介绍了在他们眼里 8 个 Web 设计趋势&#xff1a;单页面、用照片做背景、色块设计、超大号的图片、聚焦简洁、响应式设计、视差滚动、强调字体&#xff0c;每个趋势后面都附了数个案例&#xff0c;相信对网站设计师会有一定的参考价…

使用Jasmine,Spock和Nashorn测试JVM服务器端JavaScript

JavaScript使用不仅限于浏览器中的客户端代码或NodeJS支持的服务器端代码。 许多基于JVM的项目都将其用作内部脚本语言。 测试这种功能既不简单也不标准。 在本文中&#xff0c;我打算演示一种使用成熟的工具&#xff08;例如Jasmine &#xff0c; Spock和Nashorn在服务器端JVM…

带有Hibernate OGM的NoSQL –第一部分:持久化您的第一个实体

Hibernate OGM的第一个最终版本已经发布 &#xff0c;团队从发布狂潮中恢复了一些。 因此&#xff0c;他们考虑建立一系列教程式博客&#xff0c;使您有机会轻松地从Hibernate OGM重新开始。 感谢Gunnar Morling&#xff08; gunnarmorling &#xff09;创建了本教程。 介绍 不…

为自己写程序之JavsScript代码段测试器

JavaScript的测试&#xff0c;通常是在Firefox的firebug插件中测试的。不过有时只是测试几行代码都要写一个html&#xff0c;再打开浏览器测试运行结果&#xff0c;感觉并不是很方便。 今天花了点时间做了一个简易的JS片段测试器。其实这主要是看了IronJs开源项目以后&#xff…

sizeof和strlen的区别(其中涉及NUL的讲解)

本文是自己结合平时所学的知识&#xff0c;对sizeof和strlen的区别进行了总结&#xff0c;如有不对的地方还请批评指证&#xff0c;共同进步&#xff01;&#xff01;&#xff01; 一、从C语言的定义上来讲 1、sizeof是关键字&#xff0c;而strlen是包含在string.h头文件中的一…

使用WildFly和Java EE 7映像与Docker提供者一起流浪

什么是无业游民&#xff1f; Vagrant是创建虚拟开发环境的简化且可移植的方式。 它可与多种虚拟化软件一起使用&#xff0c;例如VirtualBox&#xff0c;VMWare&#xff0c;AWS等。 它还可以与多种配置软件一起使用&#xff0c;例如Ansible&#xff0c;Chef&#xff0c;Puppet或…

休眠锁定模式–乐观锁定模式如何工作

显式乐观锁定 在上一篇文章中 &#xff0c;我介绍了Java持久性锁定的基本概念。 隐式锁定机制可防止丢失更新 &#xff0c;它适用于我们可以主动修改的实体。 虽然隐式乐观锁定是一种广泛使用的技术&#xff0c;但是很少有人了解显式乐观锁定模式的内部工作原理。 当锁定的实…

如何在JMeter中执行客户端Web性能测试?

在本文中&#xff0c;我们将看到如何使用Jmeter插件进行客户端性能测试。 我将使用jmeter webdriver插件。 在开始本主题之前&#xff0c;请从我以前的文章中获得有关客户端性能测试的一些基本信息。 因此&#xff0c;让我们开始吧&#xff1a; 安装 通过这篇文章之后的链接&…

[转载]Buffon投针实验:究竟为什么是pi?

Buffon投针实验&#xff1a;究竟为什么是pi&#xff1f; Brain Storm | 2009-11-06 20:16| 57 Comments | 本文内容遵从CC版权协议 转载请注明出自matrix67.com数学学习真正悲哀的就是&#xff0c;记住了某个神奇而伟大的定理&#xff0c;看懂了其最严密的推导过程&#xff0c;…

初始化懒惰关系以及何时使用它们的5种方法

实体之间关系的延迟加载是JPA中公认的最佳实践。 它的主要目标是仅从数据库中检索请求的实体&#xff0c;并仅在需要时加载相关实体。 如果我们只需要请求的实体&#xff0c;那是一个很好的方法。 但是&#xff0c;如果我们还需要一些相关实体&#xff0c;它会增加工作量&#…

fieldset ----- 不常用的HTML标签

fieldset 元素可将表单内的相关元素分组。 <fieldset> 标签将表单内容的一部分打包&#xff0c;生成一组相关表单的字段。 当一组表单元素放到 <fieldset> 标签内时&#xff0c;浏览器会以特殊方式来显示它们&#xff0c;它们可能有特殊的边界、3D 效果&#xff…

使用入站适配器公开HTTP Restful API。 第1部分(XML)

1.简介 这篇文章的目的是使用Spring Integration HTTP入站适配器实现HTTP Restful API。 本教程分为两个部分&#xff1a; XML配置示例&#xff08;同一篇文章&#xff09;。 Java DSL示例。 这将在本教程的下一部分中进行说明&#xff0c;展示如何使用Spring Integration Ja…