进阶篇

3.线程本地存储

这个和前面提到的两个略有不同。ThreadLocal是在Thread类之外实现的一个功能(java.lang.ThreadLocal),但它会为每个线程分别存储一份唯一的数据。正如它的名字所说的,它为线程提供了本地存储,也就是说你所创建出来变量对每个线程实例来说都是唯一的。和线程名,线程优先级类似,你可以自定义出一些属性,就好像它们是存储在Thread线程内部一样,是不是觉得酷?不过先别高兴得太早了,有几句丑话得先说在前头。

创建ThreadLocal有两种推荐方式:要么是静态变量,要么是单例实例中的属性,这样可以是非静态的。注意,它的作用域是全局的,只不过对访问它的线程而言好像是本地的而已。在下面这个例子中,ThreadLocal里面存储了一个数据结构,这样我们可以很容易地访问到它:

1

2

3

4

5

6

7

8

public static class CriticalData

{

public int transactionId;

public int username;

}

public static final ThreadLocal globalData =

new ThreadLocal();

一旦获取到了ThreadLocal对象,就可以通过 globalData.set()和globalData.get()方法来对它进行操作了。

全局变量?这不是什么好事

也尽然。ThreadLocal可以用来存储事务ID。如果代码中出现未捕获异常的时候它就相当有用了。最佳实践是设置一个UncaughtExceptionHandler,这个是Thread类本身就支持的,但是你得自己去实现一下这个接口。一旦执行到了UncaughtExceptionHandler里,就几乎没有任何线索能够知道到底发生了什么事情了。这会儿你能获取到的就只有Thread对象,之前导致异常发生的所有变量都无法再访问了,因为那些栈帧都已经被弹出了。一旦到了UncaughtExceptionHandler里,这个线程就只剩下最后一口气了,唯一能抓住的最后一根稻草就是ThreadLocal。

我们来试下这么做:

1

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

我们可以将一些与错误相关的有价值的上下文信息给存储到里面添。ThreadLocal还有一个更有创意的用法,就是用它来分配一块特定的内存,这样工作线程可以把它当作缓存来不停地使用。当然了,这有没有用得看你在CPU和内存之间是怎么权衡的了。没错,ThreadLocal需要注意的就是会造成内存空间的浪费。只要线程还活着,那么它就会一直存在,除非你主动释放否则它是不会被回收的。因此如果使用它的话你最好注意一下,尽量保持简单。

4. 用户线程及守护线程

我们再回到Thread类。程序中的每个线程都会有一个状态,要么是用户状态,要么是守护状态。换句话说,要么是前台线程要么是后台线程。主线程默认是用户线程,每个新线程都会从创建它的线程中继承线程状态。因此如果你把一个线程设置成守护线程,那么它所创建的所有线程都会被标记成守护线程。如果程序中的所有线程都是守护线程的话,那么这个进程便会终止。我们可以通过Boolean .setDaemon(true)和.isDaemon()方法来查看及设置线程状态。

 什么时候会用到守护线程?

如果进程不必等到某个线程结束才能终止,那么这个线程就可以设置成守护线程。这省掉了正常关闭线程的那些麻烦事,可以立即将线程结束掉。换个角度来说,如果一个正在执行某个操作的线程必须要正确地关闭掉否则就会出现不好的后果的话,那么这个线程就应该是用户线程。通常都是些关键的事务,比方说,数据库录入或者更新,这些操作都是不能中断的。

专家级

5. 处理器亲和性(Processor Affinity)

这里要讲的会更靠近硬件,也就是说,当软件遇上了硬件。处理器亲和性使得你能够将线程或者进程绑定到特定的CPU核上。这意味着只要是某个特定的线程,它就肯定只会在某个特定的CPU核上执行。通常来讲如何绑定是由操作系统的线程调度器根据它自己的逻辑来决定的,它很可能会将我们前面提到的线程优先级也一并考虑进来。

这么做的好处在于CPU缓存。如果某个线程只会在某个核上运行,那么它的数据恰好在缓存里的概率就大大提高了。如果数据正好就在CPU缓存里,那么就没有必要重新再从内存里加载了。你所节省的这几毫秒时间就能用在刀刃上,在这段时间里代码可以马上开始执行,也就能更好地利用所分配给它的CPU时间。当然了,操作系统层面可能会存在某种优化,硬件架构当然也是个很重要的因素,但利用了处理器的亲和性至少能够减小线程切换CPU的机率。

由于这里掺杂着多种因素,处理器亲和性到底对吞吐量有多大的影响,最好还是通过测试的方式来进行证明。也许这个方法并不是总能显著地提升性能,但至少有一个好处就是吞吐量会相对稳定。亲和策略可以细化到非常细的粒度上,这取决于你具体想要什么。高频交易行业便是这一策略最能大显身手的场景之一。

处理器亲和性的测试

Java对处理器的亲和性并没有原生的支持,当然了,故事也还没有就此结束。在Linux上,我们可以通过taskset命令来设置进程的亲和性。假设我们现在有一个Java进程在运行,而我们希望将它绑定到某个特定的CPU上:

1

taskset -c 1 “

href="http://cpro.baidu.com/cpro/ui/uijs.php?

c=news&cf=1001&ch=0&di=128&fv=11&jk=30cdc418629cf3dd&k=

java&k0=java&kdi0=0&luki=10&n=10&p=baidu&q=06011078_cpr

&rb=0&rs=1&seller_id=1&sid=ddf39c6218c4cd30&ssp2=1&stid=0

&t=tpclicked3_hc&tu=u1922429&u=http%3A%2F%2Fwww%2Eadmin10000

%2Ecom%2Fdocument%2F5854%2Ehtml&urlid=0" target="_blank"

mpid="4" style="text-decoration: none;">

java

AboutToBePinned”

如果是一个已经在运行了的进程:

1

taskset -c 1

要想深入到线程级别还得再加些代码才行。所幸的是,有一个开源库能完成这样的功能:Java-Thread-Affinity。这个库是由OpenHFT的Peter Lawrey开发的,实现这一功能最简单直接的方式应该就是使用这个库了。我们通过一个例子来快速看下如何绑定某个线程,关于该库的更多细节请参考它在Github上的文档:

1

AffinityLock al = AffinityLock.acquireLock();

这样就可以了。关于获取锁的一些更高级的选项——比如说根据不同的策略来选择CPU——在Github上都有详细的说明。

结论

本文我们介绍了关于线程的5点知识:线程名,线程本地存储,优先级,守护线程以及处理器亲和性。希望这能为你日常工作中所用到的内容打开一扇新的窗户,期待你们的反馈!还有什么有关线程处理的方法可以分享给大家的吗,请不吝赐教。

私信加关注回复学习 领取最新学习资料

java中none applicable_Java线程使用技巧学习(二)相关推荐

  1. java中的后台线程、前台线程、守护线程区别

    java中的后台线程.前台线程.守护线程区别 区别和联系 区别 联系 区别和联系 区别 后台线程和守护线程是一样的. 后台线程不会阻止进程的终止,而前台线程会, 可以在任何时候将前台线程修改为后台线程 ...

  2. Java中如何实现线程的超时中断

    转载自  Java中如何实现线程的超时中断 背景 之前在实现熔断降级组件的时候,需要实现接口请求的超时中断.意思是,业务在使用熔断降级功能时,在平台上设置了一个超时时间,如果请求进入熔断器开始计时,接 ...

  3. Java中枚举的线程安全性及序列化问题

    转载自  Java中枚举的线程安全性及序列化问题 Java SE5提供了一种新的类型-Java的枚举类型,关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序 ...

  4. Java中接口、抽象类与内部类学习

    2019独角兽企业重金招聘Python工程师标准>>> Java中接口.抽象类与内部类学习 接口与内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类和抽象方法 抽象方 ...

  5. 什么是Java中的守护程序线程?

    谁能告诉我Java中有哪些守护程序线程? #1楼 守护程序线程就像其他与守护程序线程在同一进程中运行的线程或对象的服务提供者一样. 守护程序线程用于后台支持任务,仅在执行正常线程时才需要. 如果正常线 ...

  6. Java中的守护程序线程

    Daemon thread in java can be useful to run some tasks in background. When we create a thread in java ...

  7. Java中如何创建自定义的注解学习笔记(MD版)

    概要 Java中如何创建自定义的注解学习笔记(MD版). 博客 博客地址:IT老兵驿站. 前言 记得这篇笔记还是在泉州的龙玲酒店记录的,是一个周六的晚上,坐飞机从上海到泉州,从笔记中能勾起一些旅游的回 ...

  8. 12月29日--Java中有关类与对象的学习记录

    1.12月29日第一课记录 Java中有关类与对象的学习记录 一.基本概念部分 1.类:具有相同.相似的属性.特征.行为方式以及功能的一类事物的总称 (举例:一类用户,如淘宝用户) 类是对象的模板 是 ...

  9. java中我爱你_Java线程学习(转)

    编写具有多线程能力的程序经常会用到的方法有: run(),start(),wait(),notify(),notifyAll(),sleep(),yield(),join() 还有一个重要的关键字:s ...

最新文章

  1. 删除本地文件后 Git pull从远程仓库重新获取不到解决办法
  2. 目前比较流行的Python科学计算发行版
  3. python legb_理解 Python 的 LEGB.
  4. 于.net开发平台项目案例集锦
  5. 醒醒吧!送给那些盲目自学的人
  6. linux 转码软件,分享|Linux 桌面中 4 个开源媒体转换工具
  7. 微软拆分 VS Code 中 Python 扩展,部分功能可独立下载
  8. 编译安装libmemcached库报错
  9. 【招】阿里云技术战略高级专家
  10. 国二java好过还是office好过,计算机二级考哪一个科目比较容易过,Ms office 较为简单实用...
  11. 【初识SciPy库】
  12. 信息学奥赛一本通 1325:【例7.4】 循环比赛日程表
  13. android 局域网图片 管理,支持局域网浏览/简洁美观的安卓文件管理器-es文件管理器...
  14. 以阿里IoT开发物联网和应用平台
  15. 【即时通讯软件系统——开题报告 分享(仅供参考呀)】
  16. 万能险生存金什么意思,一文告诉你!
  17. OAuth2.0最简向导(多图预警)
  18. [windows优化]win10折腾过程
  19. 程序员面试100题之七 最长公共子字符串
  20. 房地产稳经济作用正在显现

热门文章

  1. udp协议服务器客户端流程图,UDP 协议通信服务器端客户端.doc
  2. 机器视觉--入门小结
  3. linux chmod修改权限失败,Linux chmod修改文件夹权限
  4. linux tcp 监控,Zabbix 监控tcp连接的状态
  5. java的断点条件,java – 非行依赖的条件断点
  6. python 天气预报 mysql_python + docker, 实现天气数据 从FTP获取以及持久化(二)-- python操作MySQL数据库...
  7. 将图片储存在dataset_最新15-16方联体垃圾箱价格图片
  8. C++基础与深度解析第一章:C++初探笔记
  9. frm文件导入mysql5.7_使用frm,ibd文件恢复数据库文件,mysql5.7.31,centos7.5,20200813...
  10. matlab实现cnn代码,CNN 经典的卷积神经网络MATLAB实现源码,可直接运行。 276万源代码下载- www.pudn.com...