多线程面试题

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线程都会在操作系统级别上打开一个新的本机线程,并且您为每个平台以不同的方式将您设置的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线程?

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

专家

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. win10设置pg/pc接口_旧电脑升级!使用固态硬盘必做的5件事,让win10操作流畅如win7...

    2020年了,win10的重大更新再次来袭! 所以,你的电脑准备好了吗? 相信很多小伙伴都意识到了,win10的大势不可挡,而面对这种情况,有许多朋友都会考虑从[HDD机械硬盘]转换到[SSD固态硬盘 ...

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

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

  4. t420i升级固态硬盘提升_旧电脑升级!使用固态硬盘必做的5件事,让win10操作流畅如win7...

    阅读本文前,请您先点击上面的蓝色字体"晓艳姐姐",再点击"关注",这样您就可以免费收到最新内容了.每天都有分享,完全是免费订阅,请放心关注. 2020年了,wi ...

  5. kindle fire1代_启动新的Kindle Fire时要做的8件事

    kindle fire1代 The Amazon Kindle Fire is a great tablet, but it's a little sparse when you first take ...

  6. java lock 效率_工作常用4种Java线程锁的特点,性能比较、使用场景

    多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...

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

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

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

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

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

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

最新文章

  1. 利用编码特长,我赚取了每月1000美元的额外收入
  2. 打印二叉树和为某一值的路径
  3. Python中的高阶函数map
  4. 互联网广告系统综述一生态圈
  5. 怎样重建一个损坏的调用堆栈(callstack)
  6. [C#] 谈谈异步编程async await
  7. win10 中午未使用 内存占用增高_清理磁盘空间【win10篇】
  8. 【293天】我爱刷题系列052(2017.11.25)
  9. css 中引入第三方字体
  10. 用计算机弹雅俗共赏,聊聊雅俗共赏:钢琴、饺子和面
  11. 面经——操作系统(linux为例)
  12. 串结构练习--字符串匹配
  13. golang算法—— 使用两个栈实现一个队列
  14. 2020身高体重标准表儿童_2020年最新身高体重对照表来啦!快来看看您的娃达标没...
  15. 信息安全三要素CIA
  16. OSChina 周二乱弹 —— 求借妹纸肩膀一用!
  17. CUDA C编程向量加法-第3章 CUDA 简介
  18. 【数据结构 C描述】一个文本串可用事先给定的字母映射表进行加密。
  19. MT6701磁编码器使用指南,14Bit单圈绝对值,I2C stm32 HAL库读角度,兼容AS5600
  20. 初级计算机知识试题,初级计算机操作知识试题.doc

热门文章

  1. 心率检测实现报告(三)
  2. 蓝桥杯web:3.【功能实现】封装函数实现个人所得税计算器
  3. B站手机APP缓存视频(m4s)转换为mp4格式
  4. 清华EMBA课程系列思考之十四 -- 战略管理
  5. “一年前,我来到国企搞IT”
  6. 小组取什么名字好_寓意兴旺的公司名字取什么名字好
  7. 名字真好听的五子棋——12周进度
  8. vue上传大文件/视频前后端(java)代码
  9. .xz是什么文件怎么解压_如何解压缩 tar.xz 文件
  10. Windows系统下编译torch-points-kernels