论坛首页 编程语言技术论坛

高手问答:Java多线程编程实战指南(设计模式篇)--获奖名单公布

浏览 14761 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2015-11-26  
一直看不懂volatile这个关键字是干啥的,楼主能否深入讲解一下。
谢谢
0 请登录后投票
   发表时间:2015-11-26   最后修改:2015-11-26
tenght 写道
viscent,你好,谢谢你刚才的解答。通过我的学习,在我看来多线程的着眼点是线程的互斥,同步等,而并发编程的着眼点是如何提高多个CPU利用率,现在大数据、云计算挺热门的,那么,在大数据处理过程中,高并发肯定是不可避免的,那么再加上多线程,大数据处理这一块我也不是很懂,是不是会大大增加编程的复杂程度呢?在这方面有没有好的学习建议?
谢谢

你的问题提的很好,我个人也是比较注重的学习方法的。这点,我也尽可能地体现在我的书中。

我认为学一样东西,要从把握它的基本概念和原理入手。并在这个过程中注意概念和概念之间的关系,知其然而知其所以然,并主动去思考一些问题。当然,“绝知此事需躬行”,自己动手去实践是少不了的。

比如拿你上面的描述中涉及的几个概念来说。“互斥”,站在它背后的是共享可变数据(Shared Mutable Data/Variable),也就是说的出现或者之所以需要它完全是因为我们在多个线程间共享了可以改变的数据。换句话说,如果多个线程之间不共享数据(参见本书第10章)或者共享的数据是不可变的(参见本书第3章),那么我们就无需互斥,程序的计算效率也就提高了。因此,多线程并不一定就意味着“互斥”。互斥的结果是某些代码在任意一个时刻只有一个线程能够执行,那么我们可以思考下面这样一个问题:

synchronized块可以实现互斥,那么synchronized块保护的是临界区代码么?

这个问题如果回答“是”,我认为也没有错。但是,如果深入一步理解,我们会发现synchronized块正在要“保护”的是临界区代码所访问的共享可变变量,而不是代码本身。

在比如说“同步”(同步机制),为什么需要同步呢?一方面是要用它来“保护”共享可变数据。另外,也是通过它来保证多线程间共享的数据(不一定是可变的)之间的内存可见性(Visibility);并且,禁止指令重排序也是通过同步机制实现的。这里,又涉及了一个概念“”内存可见性“,站在它背后的是CPU通过缓存(Cache)去访问内存以提高其处理效率这个事实以及JIT编译器处于对代码执行效率的考虑可能对代码作出的优化。同样,指令重排序是个什么概念,什么情况下我们需要禁止(或者阻止)指令重排序也是我们要掌握的概念和原理。

再比如说,我们都知道Java中有两种方法可以创建线程,那么这两种方法有什么区别呢?当我们掌握了线程安全这一概念以后,思考这个问题的答案就有了方向了。

我们经常说“多线程编程”、“并发编程”,往往也不对二者进行区分。那么,二者有什么联系和区别呢?

线程(多线程)其实只是一种并发编程的模型,也就是说多线程可以实现并发编程。而并发编程却不一定就是多线程编程,有其它的方法,如Actor模型也能实现并发编程。当然,线程模型可以是其它并发编程模型的基础。这样把概念弄清楚,有助于我们扩展思路,开阔眼界。例如,本书第8章介绍的Active Object模式其背后的思想和Actor模型非常相似。

反过来说,不能真正掌握基本概念和原理,就会导致表面上我们是学会了某些东西,但是在实际的工作过程中一遇到问题以自己的力量(不问别人、不搜索)就搞不定了。这好比驾校老师教学生如何发动小汽车、如何变道、如何换挡等等,学生也能自己操作起来。但是,学生考到驾照后,自己上路的时候就会遇到许多实际的问题,比如车子熄火了怎么办?路过积水的涵洞怎么办?这些自己能搞定么?再拿我们工作中的实际例子来说,如果我们不能理解到JSP就是一个Servlet的这个事实,不知道JSP经历从翻译、编译到运行的这样一个处理过程,那么在遇到JSP问题的时候我们自己可能就搞不定,比如一个JSP中include了另外一个JSP,被include的JSP内容更新了,而主JSP在运行的时候却始终没有出现更新后的效果。这样的问题,没有本质上把握JSP的概念和处理原理,仅凭自己是很难搞定的。

问题人人都会遇到,区别是老手能够很快找到问题所在,并给出简单有效的解决方法,而新手可能一直在原地踏步,甚至走进死胡同。究其原因,经验差别固然是一方面,我上面所讲应该也是重要的一方面。

至于大数据、云计算,我在工作过程中并没有接触。但是,我想方法是相似的。如果是我学它们,我会从这些技术或者理念的出现是要解决什么问题以及它们的一些基本概念和原理入手。另外,如果时间上允许的话,我建议是先学一样技术,深入的学习并掌握它,再次基础上再去学习其它知识、技术。这样,对于后学的东西而言,我们可以充分利用之前学习到知识、经验以及积累的能力,可以使学习后学的东西轻松一点。这种现象心理学上称之为”迁移“,类似我们所说的”触类旁通“。
1 请登录后投票
   发表时间:2015-11-26  
1:在传统的bs项目中(数据量没有那么大)哪些场景可以用多线程。
2:总听别人说,多线程上下文切换耗资源啥的,没有明白他怎么具体耗资源了,另外解决这种上下文切换耗资源有哪些方案。
0 请登录后投票
   发表时间:2015-11-27  
谢谢 viscent 老师给我一个思路;通过老师的分享我也知道目前是没有一套完美线程测试工具去解决这个多线程测试问题;那我有一个问题,类似java的jstack 它可以输出dumpthread 文件,它是怎么监控到这些线程的状态和信息,如何知道死锁线程呢;这其中原理是啥?谢谢老师
0 请登录后投票
   发表时间:2015-11-27  
viscent老师,您好。我想问你两个问题!
1.怎么能培养起编写稳定安全的多线程代码的思维呢?
    就自身而言,在实际过程中,写多线程的代码的时候,当类多起来的时候,就容易混淆类之间的调用关系,就开始乱了,对于自己编写的代码,对于安全和稳定性就不能给以信心的保证了。
2.您的书中写了很多多线程模式,应该在哪些地方多研究,才能深刻理解这些多线程编写代码的思维呢?
0 请登录后投票
   发表时间:2015-11-27   最后修改:2015-11-27
viscent大神你好,入这行业三年了,没去过大公司,基本上也就把功能实现了就可以,所以知识面尚浅,就目前来说的话看你这书还是有些吃力,像计算机硬件方面(如缓存cache.线程)也没有一定得功底,所以我想请教一下怎么个深入法,有没一个比较好的规划性建议,谢谢
0 请登录后投票
   发表时间:2015-11-27  
viscent大神你好,入这行业三年了,没去过大公司,基本上也就把功能实现了就可以,所以知识面尚浅,就目前来说的话看你这书还是有些吃力,像计算机硬件方面(如缓存cache.线程)也没有一定得功底,所以我想请教一下怎么个深入法,有没一个比较好的规划性建议,谢谢
0 请登录后投票
   发表时间:2015-11-27  
感觉挺不错的,一看就是很有实战经验的程序员,试读的两个章节,我在实际项目中也深有体会,作者很善于归纳总结,对我有很好的借鉴之处,支持一下!另外有些细节想了解一下,第五章中ConcurrentLinkedQueue中为什么用的是WeakReference弱引用呢?如果用其它引用如softreference会有什么问题呢?
0 请登录后投票
   发表时间:2015-11-27  
肖泽文 写道
viscent大神你好,入这行业三年了,没去过大公司,基本上也就把功能实现了就可以,所以知识面尚浅,就目前来说的话看你这书还是有些吃力,像计算机硬件方面(如缓存cache.线程)也没有一定得功底,所以我想请教一下怎么个深入法,有没一个比较好的规划性建议,谢谢


引用张龙老师在本书的推荐序中提到的:
“每一名有理想的Java 开发者都应该系统学习有关多线程编程的知识,这不仅涉及程序语言与库的学习,还需要了解现代硬件体系架构(如CPU、缓存、内存等),同时辅以恰当的设计模式,这样才能在未来游刃有余、得心应手。 ”

因此,我想你就是这样一名有理想的开发者!总得来说,我建议还是从基础做起。没有牢固的基础,一切就成了无源之水。至于如何学习基础,我之前回复过类似的问题,已整理到我的博客上。

你提到的硬件基础,我觉得也没有必要太过担心。可以从一些最为基础但是又和多线程编程紧密相关的知识入手。比如,虽然我们一提到变量就联想到内存,而实际上CPU内部有其存储子系统(如寄存器、Cache),它并不是直接访问内存,而是通过其缓存(包括一级缓存、二级缓存、三级缓存等)访问内存的。那么,理解到这点,我们就会发现一个问题,那就是运行在多个CPU上的线程各自访问该CPU中的缓存内容的时候,其中个别CPU更改了变量的值(更改到Cache中),如何保证其它线程也能看到这个更新后的值呢?这个问题,从CPU的角度说,就涉及缓存一致性(协议)问题。从软件的角度看,就涉及可见性问题。当我们了解了缓存一致性协议的概念了,那么问题又来了。既然缓存一致性协议能够保证各个CPU上对内存中变量的缓存值的一致性,那么从软件的角度来看,我们又为什么有可见性的问题。思考这个问题,又会带领我们去考虑另外一个硬件组件——写缓冲器Write Buffer。CPU写变量的时候还不是直接写入Cache,而是写入Write Buffer。认识Writer Buffer这个东西之后,我们就理解内存屏障Memory Barrier这个概念了。认识这个概念后,对于软件层面的锁、volatile关键字、final关键字就会有一个深入的理解。

以上只是说明我在博客中回复的学习思路和方法,你不必急于其理解其中的细节。
在基础知识牢固,并有了一定的实践经验的条件下,就可以学习多线程相关的设计模式,它又有助于你去解决实践中遇到的问题。


0 请登录后投票
   发表时间:2015-11-27   最后修改:2015-11-27
ChinaWxr 写道
感觉挺不错的,一看就是很有实战经验的程序员,试读的两个章节,我在实际项目中也深有体会,作者很善于归纳总结,对我有很好的借鉴之处,支持一下!另外有些细节想了解一下,第五章中ConcurrentLinkedQueue中为什么用的是WeakReference弱引用呢?如果用其它引用如softreference会有什么问题呢?

感谢你的肯定!使用WeakReference主要是希望:
1、TerminationToken实例对线程对象的引用不阻碍JVM进行垃圾回收,以避免可能出现的内存泄漏
2、如果TerminationToken实例间接引用的线程对象可以被回收,希望这个回收能够尽量块的发生(而不是像使用SoftRefence那样可能被推迟)。毕竟线程对象会消耗宝贵的资源。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics