java 内部thread_Java代码质量改进之:使用ThreadLocal维护线程内部变量

在上文中,《Java代码质量改进之:同步对象的选择》,我们提出了一个场景:火车站有3个售票窗口,同时在售一趟列车的100个座位。我们通过锁定一个靠谱的同步对象,完成了上面的功能。

现在,让我们反过来,每个窗口负责一趟车。比如一号窗口就卖1号列车的票,二号窗口就卖2号列车的票。不过它们需要同时开始卖票。

一:ThreadLocal的最简应用

首先,既然是各卖各的火车了,那么,就不需要同步了。于是代码又回归到:

02f56e179035a30ad12bde85c270af5d.png

但是当前的代码肯定是不对的,每个线程访问的都是同一个火车的ticket,并且还会出现超售现象。要保证每new一个窗口出来,就有一趟自己的列车,我们就可以用到ThreadLocal对象了。

让我们首先替换掉ticket变量,改为:

716c3b933b6d6a4ed4a4147e6f3fa96d.png

然后,售票的代码改为:

27f3070391d17191b2105c9dc61c1b9a.png

虽然ticket依然是一个static变量,但是,运行程序你会发现,新起一个线程,不同的线程还是会拥有自己的ticket,不会互相干扰。也就是实现了每个窗口卖自己那趟车的目标。

二:ThreadLocal VS 实例变量

每一个程序员都应该是杠精。为什么,因为回过神来的我们发现,只要回到第一段代码中,把ticket中的static去掉,就能达到同样的目的:

72ca333871fc6336ec8b7b4553f843d0.png

试下上面的代码,是不是也能达到各卖各的目的?

我们是脑袋被门板挤了,才想出来一个TheadLocal这样的复杂方案吗?

如果单纯说上面的这段代码,是的。但是,还有很多的场合,是ThreadLocal的用武之处。比如,我们并不永远使用extends Thead的方式来写多线程,我们还可能用implements Runnable的方式来写多线程(ps:还有更多的写法哦),如下:

7ed9de33ebe3294227c6846481c827d9.png

而在这种情况下,我们就不得不使用TheadLocal了,这里就不放出代码了,大家可以试一下。

甚至,更进一步的,我们是不是能够把ticket这个变量放进方法内部呢,如果放入方法

内部的话,我们同样也是必须要使用ThreadLocal才能达到实现目的,如下:

efcd28292407c5960cdc680f51c586e7.png

总之,简单来说:当要运行的代码本身不是很方便访问当前的线程实例的时候,就是ThreadLocal的用武之地。

三:ThreadLocal的应用场景

ThreadLocal有这样一些应用场景,比如连接池管理、会话管理等等。

在连接池的管理中,当我们需要获取一个连接,就应该为每一次获取给出不同的连接。在web应用中,请求是被线程池管理的,也就是说获取连接这个行为不是单线程行为,所以我们最好就要设计成不同的线程不能获取同一个连接,要保证能做到这样,就应该使用ThreadLocal了。

可能有人会表示,那不能设计成实例变量吗?答案是:不能。因为,在web应用中,线程都不是被我们自己管理的,所以,最佳的做法就是使用ThreadLocal。一个标准的做法如下:

01232036b12d2a852fef7dc43a52944b.png

最后作为补充,我们再来看看hibernate中ThreadLocal的应用:

dafd71637ee1935ea303903509987745.png

以下是广告时间:最课程(http://zuikc.com)正在招收Java就业班学员,如果你想学习更多的Java高质量代码编写方面的技巧,请联系我们哦。

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

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

相关文章

java学习(46):无参带返回

/*1、 如果方法的返回类型为 void ,则方法中不能使用 return 返回值! *2、 方法的返回值最多只能有一个,不能返回多个值 *3、 方法返回值的类型必须兼容,例如,如果返回值类型为 int ,则不能返回 String 型值…

Luogu 4284 [SHOI2014]概率充电器

BZOJ 3566 树形$dp$ 概率期望。 每一个点的贡献都是$1$,在本题中期望就等于概率。 发现每一个点要通电会在下面三件事中至少发生一件: 1、它自己通电了。 2、它的父亲给它通电了。 3、它的儿子给它通电了。 那么我们设$f_i$表示它的父亲给它通电的概率&…

java 域的隐藏_Windows Server 2008R2\2012\2016使用域策略自定义隐藏指定驱动器

Windows Server 2008R2\2012\2016使用域策略自定义隐藏指定驱动器最近在做项目的时候需要对Win7客户端的部分驱动器进行隐藏,但域策略默认的隐藏选项不能满足需求,根据微软官方文档https://support.microsoft.com/zh-cn/help/231289/using-group-policy-…

java学习(47):带参无返回

//带参无返回值 /*注意: 1、 调用带参方法时,必须保证实参的数量、类型、顺序与形参一一对应 2、 调用方法时,实参不需要指定数据类型 3、 方法的参数可以是基本数据类型,如 int、double 等,也可以是引用数据类型&am…

java学习(48):带参带返回

public class test14 { public String show(String name) { return “欢迎您,” name "!"; } public static void main(String[] args) {test14 hello new test14();hello.show("歌谣");System.out.println(hello.show("歌谣")); }}

java学习(49):方法重载

定义一个computer类 public class computer { public void runSoftWor(vidio vedio){ System.out.println("视频长度是 "vedio.getLength()); } public void runSoftWor(Voice voice){System.out.println("歌曲的名字是 "voice.getTitle()); }public bool…

java学习(50):子类继承会优先调用父类的构造器

定义一个父类 public class Parent { public void run(){ System.out.println(“我会跑步”); } public Parent(){ System.out.println(“我是爸爸”); } } 定义一个子类 public class Son extends Parent { public Son(){ System.out.println(“我是儿子”); } } 定义一个测试…

Get Requests with Json Data Get Requests with Url Parameters

转载于:https://www.cnblogs.com/chengchengla1990/p/9883536.html

java学习(51):上转型对象

定义一个animal类 //java上转型对象 public class Animal { public String name“动物”; public String getName(){ return name; } public void action(){ System.out.println(“动物都在我的分类之中”); } public void feature(){ System.out.println(“我们都很帅气”); }…

java学习(52):抽象类

//定义一个人的抽象类 public abstract class Person { public abstract void eat();//吃饭 public abstract void drink();//喝水 public abstract void play();//玩 } //定义一个富人的抽象类 public abstract class Rich extends Person{ public abstract void buy();//买 p…

玩转oracle 11g(9):crud操作(亲测)

oracle支持的数据类型 字符类 char 定长 最大2000个字符。 例子:char(10) ‘小韩’前四个字符放‘小韩’,后添6个空格补全 如‘小韩’ varchar2(20) 变长 最大4000个字符。 例子:varchar2(10) ‘小韩’ oracle分配四个…

项目管理(1):备战pmp

1什么是项目  一家公司被收购  海外建设通讯站点  研究院研发一种新型的药物  中国当局缉拿新疆针刺袭击嫌疑人  野生动物湿地保护区的建立  与朋友一起旅游  房屋装修  ………………请问哪些是项目? 2项目的发展历程  1900年代早期,H…

神经网络中使用Batch Normalization 解决梯度问题

BN本质上解决的是反向传播过程中的梯度问题。 详细点说,反向传播时经过该层的梯度是要乘以该层的参数的,即前向有: 那么反向传播时便有: 那么考虑从l层传到k层的情况,有: 上面这个 便是问题所在。因为网络…

项目管理(2):备战pmp

1项目阶段与项目生命周期 将每一个项目划分为若干个阶段(phases),以便提高管理控制,并提供与该项目实施组织的日常运作之间的联系 这些阶段合在一起称为项目生命周期 项目的生命周期用于定义一个项目的开始和结束 许多组织识别出一…

2018-2019-1 20189213《Linux内核原理与分析》第四周作业

《Linux内核原理与分析》第四周学习总结: 1.课本知识总结: 本章内容并不多,首先是介绍了一些Linux内核源代码的目录结构,并基于Linux内核源代码构造一个简单的操作系统MenuOS,同时在MenuOS启动过程中跟踪分析Linux内核…

matlab窗函数带通滤波器,Matlab结合窗函数法设计数字带通FIR滤波器

Matlab结合窗函数法设计数字带通FIR滤波器 课程设计任务书学生姓名: 专业班级: 通信工程 指导教师: 工作单位: 信息工程学院 题 目:利用 Matlab 仿真软件系统结合窗函数法设计一个数字带通 FIR 滤波器初始条件: 1.《数…

java学习(53):接口的定义和创建

定义一个computer类 package com.company; public interface computer{ /定义公告,静态,常量/ public static final int MAX_NUM5000; /接口中只允许定义公共的抽象方法/ public abstract double couunt(double num1,double num2,char tag); } 定义一个…

java学习(54):接口之间的继承

定义一个接口类 //接口 interface interface4 { public abstract void fly(); public abstract void eat(); } //定义一个老鹰类 public class interface3 implements interface4{ public void fly(){ System.out.println(“我是老鹰,我会飞”); } public void eat…

Java排查问题随笔

常言道:“好记性不如烂笔头”,确实很有道理。在日常工作中,偶尔处理下线上问题还是很常见的,经常出现的情况就是忘记一些常用命令(套路)的用法了,因此整理下来非常用必要,以便关键时…

java学习(55):定义一个抽象类的继承

不同的是定义一个抽象类先 //抽象类 public abstract class interface4 { public abstract void fly(); public abstract void eat(); } //定义老鹰类继承 /定义一个老鹰类 public class interface3 extends interface4{ public void fly(){ System.out.println(“我是老鹰&…