《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)

《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)

开篇介绍

感谢图灵图书的邀请,能提前拜读Bruce Eckel 的新作《On Java 8》 ,Bruce Eckel 是《Thinking in Java》(中文版是 《Java编程思想》(第4版) )的原作者,巨佬 (大佬中的大佬)的新书值得期待。


《On Java 8》 是图灵程序设计丛书,由图灵社区组织翻译。从图灵官方得到的资料:翻译的4位译者大佬,是从200份试译稿中经过层层筛选脱颖而出《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)特色

本书适合各个层次的Java开发者阅读,同时也可作为高等院校讲授面向对象程序设计语言以及Java语言的参考教材。


对我的影响

读书时,在老师的推荐下接触到了《Java编程思想》(第4版) ,这本在我看来是“java圣经 ”。因为从我刚开始学习JAVA编程,到现在从业JAVA开发十年左右的时间里,在不同的阶段,每次阅读都会有所收获。


我的一个糗事,刚好跟大家分享分享,我差点因为这本书,放弃编程这条路。我拿到这本**《Java编程思想》(第4版)** 纸质书时,特意比了下厚度,有4个手指头的厚度,总共快900页的书,这得看到什么时候。当时满怀激情,还列下了学习计划,每天学习一两个小时这本书。有句话说得好:坚持一个月养成好习惯 。结果是,从头到尾 一章章地阅读这本书,第一周凭激情坚持了下来,第二周就坚持不下去了,内容太干货了,硬啃太难受了。而且,第二周,第三周时,之前看的内容,也忘得七七八八了。编程太难了,我想回农村。


但是老师强力推荐这本书,肯定是有价值的。是不是我的打开方式不对。难道要像易筋经那样,倒着看,侧着看?后来去请教了老师,把我读不下去的问题跟老师请教。原来真的是打开方式不对,像这类的技术书,不应该像初中高中的教科书一样从头读到尾 ,我们学习用到的教科书,大部分的结构是由浅入深,前后的知识依赖性强,不能用挑着看 这种方式。但是**《Java编程思想》(第4版)** 这本书就可以。


书中每一章都会介绍一个或者一组互相关联的概念,同时这些概念不依赖于当前章节没有介绍的特性。因此,你可以结合当前获取的知识来充分理解上下文,然后再阅读下一章。


引自 《On Java 中文版(基础卷)》前言


这本书的正确打开方式应该是,带着问题来找解决方案 。例如作业,课设和实战项目等这些就是比较好的切入点,举个例子,你要实现对文件的操作功能,包含创建文件,复制文件,文件追加文件和删除文件等功能,那就要了解第18章 JAVA I/0系统 。本章会介绍JAVA标准库中IO的各类以及它们的用法。在看的时候对某个概念不理解,就返回目录查看相关的章节内容。这样一来一回,不会枯燥,而且当把问题解决时,是会有成就感的。这种成就感,就会转化为坚持的激励。


而且里面提供了很多代码例子,跟着一个个字母码代码,结合带着问题来找解决方案 。过程是bug满地的,通过一次次的调试和修改代码,结果是问题解决了,代码量上来了,兴趣也养成了。


内容分享

分享一个实战案例:《ThreadLocal在线程池中引发的问题》


ThreadLocal引发的血案

背景

张三在开发业务系统A,发现系统的当前用户的租户信息取不到,这种情况是偶发的,遇到过几次,无法直接重现。这个问题上报到了架构组,后面流转到了我的手上。


定位问题

首先,排查了获取当前用户的租户信息接口,经过压测,没有出现问题。


然后,在张三的开发环境上尝试重现,尝试多次,还真的出现了取不到当前用户的租户信息的问题。断点跟进时,发现获取的当前用户租户信息 变了,不应该啊,相同的session会话,用户没有做登出动作,也没有新的用户登录,当前用户租户信息 不应该会变化。


跟进代码查看,当前用户标识 是存在**ThreadLocal对象 ** 里的。


所以有可能是ThreadLocal 用法没用对。


ThreadLocal介绍

**ThreadLocal ** 通过字面上就很好理解,它是线程本地化变量。


并发编程时,经常遇到多线程操作同一个变量而导致处理异常。这个就是我们常说的线程不安全问题。针对这种情况需求:都使用同一个变量,但是要求每个线程里的这个变量值不会串掉,这时候就轮到**ThreadLocal ** 出马了。


**ThreadLocal对象 ** 通常当做静态域存储。可以为使用相同变量的每个不同线程创建不同的存储。


在创建ThreadLocal 时,只能通过get() 和set() 方法来访问对象的内容。


get方法 :将返回与线程相关联的对象副本;


set方法 :将参数插入到其线程存储的对象中,并返回存储中原有的对象。


ThreadLocal源码分析《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)get方法 的代码逻辑


第一步:得到当前线程对象


第二步:获取当前线程对象的threadLocals 变量值,就是ThreadLocalMap


大家发现没,ThreadLocal 的值存储是存在线程的threadLocals 里的。而不是存在ThreadLocal 对象中。


第三步:如果map不等于null,从map中查找到本地变量的值,返回本地变量的值。


第四步:如果map为null,则返回初始化当前线程的本地变量。


初始化当前线程的本地变量方法 的代码逻辑


第一步:给变量value 设置null值,置空。


第二步:得到当前线程对象


第三步:获取当前线程对象的threadLocals 变量值,就是ThreadLocalMap


第四步:如果map不等于null,设置map的值,key为当前线程,值为设置成null的变量value


第四步:如果map为null,就要创建map,再设置值,代码如下,这个就很好理解了《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)


《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)


《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)


《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)

特色

本书适合各个层次的Java开发者阅读,同时也可作为高等院校讲授面向对象程序设计语言以及Java语言的参考教材。


对我的影响

读书时,在老师的推荐下接触到了《Java编程思想》(第4版) ,这本在我看来是“java圣经 ”。因为从我刚开始学习JAVA编程,到现在从业JAVA开发十年左右的时间里,在不同的阶段,每次阅读都会有所收获。


我的一个糗事,刚好跟大家分享分享,我差点因为这本书,放弃编程这条路。我拿到这本**《Java编程思想》(第4版)** 纸质书时,特意比了下厚度,有4个手指头的厚度,总共快900页的书,这得看到什么时候。当时满怀激情,还列下了学习计划,每天学习一两个小时这本书。有句话说得好:坚持一个月养成好习惯 。结果是,从头到尾 一章章地阅读这本书,第一周凭激情坚持了下来,第二周就坚持不下去了,内容太干货了,硬啃太难受了。而且,第二周,第三周时,之前看的内容,也忘得七七八八了。编程太难了,我想回农村。


但是老师强力推荐这本书,肯定是有价值的。是不是我的打开方式不对。难道要像易筋经那样,倒着看,侧着看?后来去请教了老师,把我读不下去的问题跟老师请教。原来真的是打开方式不对,像这类的技术书,不应该像初中高中的教科书一样从头读到尾 ,我们学习用到的教科书,大部分的结构是由浅入深,前后的知识依赖性强,不能用挑着看 这种方式。但是**《Java编程思想》(第4版)** 这本书就可以。


书中每一章都会介绍一个或者一组互相关联的概念,同时这些概念不依赖于当前章节没有介绍的特性。因此,你可以结合当前获取的知识来充分理解上下文,然后再阅读下一章。


引自 《On Java 中文版(基础卷)》前言


这本书的正确打开方式应该是,带着问题来找解决方案 。例如作业,课设和实战项目等这些就是比较好的切入点,举个例子,你要实现对文件的操作功能,包含创建文件,复制文件,文件追加文件和删除文件等功能,那就要了解第18章 JAVA I/0系统 。本章会介绍JAVA标准库中IO的各类以及它们的用法。在看的时候对某个概念不理解,就返回目录查看相关的章节内容。这样一来一回,不会枯燥,而且当把问题解决时,是会有成就感的。这种成就感,就会转化为坚持的激励。


而且里面提供了很多代码例子,跟着一个个字母码代码,结合带着问题来找解决方案 。过程是bug满地的,通过一次次的调试和修改代码,结果是问题解决了,代码量上来了,兴趣也养成了。


内容分享

分享一个实战案例:《ThreadLocal在线程池中引发的问题》


ThreadLocal引发的血案

背景

张三在开发业务系统A,发现系统的当前用户的租户信息取不到,这种情况是偶发的,遇到过几次,无法直接重现。这个问题上报到了架构组,后面流转到了我的手上。


定位问题

首先,排查了获取当前用户的租户信息接口,经过压测,没有出现问题。


然后,在张三的开发环境上尝试重现,尝试多次,还真的出现了取不到当前用户的租户信息的问题。断点跟进时,发现获取的当前用户租户信息 变了,不应该啊,相同的session会话,用户没有做登出动作,也没有新的用户登录,当前用户租户信息 不应该会变化。


跟进代码查看,当前用户标识 是存在**ThreadLocal对象 ** 里的。


所以有可能是ThreadLocal 用法没用对。


ThreadLocal介绍

**ThreadLocal ** 通过字面上就很好理解,它是线程本地化变量。


并发编程时,经常遇到多线程操作同一个变量而导致处理异常。这个就是我们常说的线程不安全问题。针对这种情况需求:都使用同一个变量,但是要求每个线程里的这个变量值不会串掉,这时候就轮到**ThreadLocal ** 出马了。


**ThreadLocal对象 ** 通常当做静态域存储。可以为使用相同变量的每个不同线程创建不同的存储。


在创建ThreadLocal 时,只能通过get() 和set() 方法来访问对象的内容。


get方法 :将返回与线程相关联的对象副本;


set方法 :将参数插入到其线程存储的对象中,并返回存储中原有的对象。


ThreadLocal源码分析《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)get方法 的代码逻辑


第一步:得到当前线程对象


第二步:获取当前线程对象的threadLocals 变量值,就是ThreadLocalMap


大家发现没,ThreadLocal 的值存储是存在线程的threadLocals 里的。而不是存在ThreadLocal 对象中。


第三步:如果map不等于null,从map中查找到本地变量的值,返回本地变量的值。


第四步:如果map为null,则返回初始化当前线程的本地变量。


初始化当前线程的本地变量方法 的代码逻辑


第一步:给变量value 设置null值,置空。


第二步:得到当前线程对象


第三步:获取当前线程对象的threadLocals 变量值,就是ThreadLocalMap


第四步:如果map不等于null,设置map的值,key为当前线程,值为设置成null的变量value


第四步:如果map为null,就要创建map,再设置值,代码如下,这个就很好理解了《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)remove方法 的代码逻辑


第一步:得到当前线程对象,获取当前线程对象的threadLocals 变量值,就是ThreadLocalMap


第二步:如果m不为null,移除当前线程中指定ThreadLocal实例的本地变量


综上所述,我们可以知道ThreadLocal 在每个线程中都有一个threadLocals 变量。这个变量的类型是ThreadLocal.ThreadLocalMap (类似hashMap),key 为当前线程,value 值为用set方法 设置的值。每个线程的ThreadLocal 都会存自己的本地内存变量threadLocals ,如果线程没有被干掉(线程池的线程是可复用的 ),那这些本地内存变量就会一直存在。


根据这个理论,找到程序有调用一个模拟登录的接口,用来处理一些特殊的业务。问题出在:只调用了模拟登录的接口,实现业务后,没有及时再调用模拟登出的接口。


模拟登录使用,如果有登录,切记要在finally代码块处理logout


模拟登录时,会把用户的租户信息存到ThreadLocal 线程中的threadLocals 变量里,又不是及时销毁,因为线程池的线程是可复用的 ,就有可能随机命中到模拟登录的数据,导致读取的数据出现异常。


问题得到了解决,经过一段时间的跟进,问题没有再次复现。


回顾

在排查问题中,其实思路是没有这么连贯的,一开始是没有考虑到线程池的线程是可复用的 和ThreadLocal 会产生这种联动反应。


是在翻阅**《Java编程思想》(第4版)** 的关于并发 的内容时,突然看到有关于ThreadLocal 的介绍,里面有提到这么一句话:


当运行这个程序时,你可以看到每个独立线程都被分配了自己的存储


灵光一亮,既然使用ThreadLocal 每个线程都有自己的存储,那就不应该数据会串掉,但结果是能读到其他数据。那就说明,使用的是同一个线程,只是这个值被其他功能覆盖掉了。然后就从这个思路去排查,最终定位到了问题。


《Java编程思想》 不愧是JAVA的名著 ,本书的内容,就像是一位技术大佬在声情并茂地给你上课,给你细细地解读JDK源码,把思想娓娓道来。


总结

1、《On Java 8》 是一本好书,但读这类的书是有技巧的,个人推荐:带着问题来找解决方案 ;


2、《On Java 8》 好在内容齐全且优质,有很丰富的代码示例,这也是为什么这本书很厚的原因之一吧;


3、这回的翻译团队强大,且翻译组的用心是可以感受到的。翻译的好坏,是很影响读者的体验。


4、本书适合各个层次的Java开发者阅读:


刚入门或者初级开发:代码量不够,那就跟着示例代码敲一遍,自己总结一遍,输出学习笔记,是提高水平的一种方式,看代码千遍,不如自己写一遍。

中级开发:常备此书,时不时翻阅下,会有一些感悟的。平时也可当工具书查阅,很实用的。

高级以及以上的开发:可以回顾整个java体系内容,务实基础。书中使用了很多的设计模式是值得学习的,感悟作者表达的思想,可以从中受益。

5、由于博主最近也在研究分析JDK源码,同时输出博客。对比下Bruce Eckel 的《On Java 8》

内容,自己只是蹒跚学步,很多方面考虑得不够周全,努力吧,向大佬学习。


推荐相关文章

高级JAVA开发必须掌握技能:java8 新日期时间API((一)JSR-310:ZoneId 时区和偏移量)


高级JAVA开发必须掌握技能:java8 新日期时间API((二)JSR-310:常用的日期时间API)


高级JAVA开发必须掌握技能:java8 新日期时间API((三)JSR-310:格式化和解析)


高级JAVA开发必须掌握技能:java8 新日期时间API((四)JSR-310:常用计算工具)


高级JAVA开发必须掌握技能:java8 新日期时间API((五)JSR-310:实战+源码分析)


高级JAVA开发必须掌握技能:java8 JSR-310判断是否闰年实现,发现原作者的代码可能有问题


要探索JDK的核心底层源码,那必须掌握native用法


万字博文教你搞懂java源码的日期和时间相关用法


java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案


源码分析:JDK获取默认时区的风险和最佳实践


高级JAVA开发必备技能:时区的规则发生变化时,如何同步JDK的时区规则


今天是持续写作的第 14 / 100 天。

可以关注我,点赞我、评论我、收藏我啦。





上一篇:vue计算属性


下一篇:高级JAVA开发必备技能:java8 新日期时间API((四)JSR-310:常用计算工具)(JAVA 小虚竹)