java多线程高并发浅谈 weir 2016-05-31 14:38:32.0 java,多线程 3288 多线程一直被认为是java的一大法宝来对抗c/c++这种经典而高效的语言。有的时候有人会做一些对比看看谁的性能好。我觉得大可不必,用什么语言应用场景更重要。当然一个完善的语言环境是一个语言发展的基石,在这方面java绝对的光彩照人。今天都机会说说java多线程说实话很惭愧,一直在java的茫茫大海中像小虾米一样苟活着,从来没有真正触碰到她的真面目。 计算机的发展你可以理解发展很快也可以说他很难,记的上大学那会儿就听说什么量子计算呀生物计算呀人工智能呀,当然也就过去不到十年,在我看来还是有点慢。 上学时候学的计算机的理论虽然忘得差不多了,但基本点没有改变。比如CPU有缓存、CPU指令的无序性,内存的高效和丢失,磁盘的读取写入速度等等,每一个环节都会影响我们的性能。 我们总是在电视上看到我们对未来的设想,人类在想着改造环境的时候总是把自己的利益放在第一位,而忽略了我们的环境才是我们生存的根本。 说到多线程就不得不说多线程的由来,我不打算试图说服计算机以外的人听懂这些。我一直在想如果把线程所干的事情拿到进程里面干会不会提高性能,当我说出这样的话时会有人嘲笑我,说实话关于进程间的通讯我真的一无所知,刚刚才上网查了一下还真可以(http://blog.csdn.net/lishenglong666/article/details/8557215) 在这篇文章中我们也许能找到一些答案。 言归正传java是多线程的操作。那就不得不说一下多线程的特点,在上面的连接文章中也有提到,这里重点要说的是共享变量,我想进程之间也有共享变量的时候,所以说不管是多进程还是多线程,共享变量也是问题的核心。如果每个线程之间是独立的没有设么可以共享的那我们还在这里讨论多进程多线程干嘛,再说如果程序里面根本没有需要共享的东西那计算机对我们还有什么用处,所以共享本身就是我们所期待的结果,只有共享世界才能连接在一起。 有共享就有同步要不然就乱套了。在java语言中通常有一个地方可以做到“同步”: 1. volatile关键词,它是最直接的把共享变量同步的关键词,因为它直接是被CPU的缓存识别直接把改变后的变量存放回内存。 2. 原子操作:关于这点大家只要理解什么是原子就ok了,简单来说原子就是计算机硬件本身就支持的数据类型。那我们可以这样想,如果计算机硬件什么类型都支持那我们在操作多线程时不就更简单了么,我想这种想法说不一定还真可以实现。 3. final关键词,严格来说他不能保障同步,但我们在很多时候对于已知不可变的数据通常会用final去修饰,因为final的数据会被存放在寄存器当中,所以寄存器是什么东东你要不要去了解一下呀。 同步还有第四点,但我不能把它在归类了,因为他是我们的主角。在主角还有没登场之前我们分析一下多线程之间的变量同步方式少得可怜,计算机硬件为我们做的也不多,完全需要靠我们自己编程控制,这就注定了多线程会成为我们关注的焦点。 synchronized关键字,让人又爱又恨的东西,开启java多线程的钥匙,人为干预CPU运行指令的命令,你可以理解它是一把锁,一个拦截器,它使得在多线程情况下同时只有一个线程可以访问。这就是我们能想到的在多线程情况下怎么保障同步的方法,采用阻塞式的方式。 说到这里不得不提另外一个神通广大的类Object。它的神奇之处很多,在多线程的领域它应该是离线程最近最容易控制线程的类。 这一个方法不难理解,资料也很多: Wait() 等待 Notify()/notifyAll() 唤醒 有了这些就可以把经典的生产者和消费者模式的问题解决了,看起来还是很简单的,并没有说要搞一大堆的方法才能实现。我们多思考思考,多线程模式下到底有哪些应用场景,哪些是制约因素,你想来想去就会发现天哪!还是共享变量数据的问题。 在这里我们不得不讨论一下多线程的本质问题,我们从刚开始引用的文章中可以发现多线程的产生是为了更轻量级的计算问题,我们同时还会发现有这么一句话:“进程是资源分配的最小单位,线程是CPU调度的最小单位” 注意“CPU调度”这几个字,很重要!我们再回头看看里面的一个比较直观的表格: 对比维度 多进程 多线程 总结 数据共享、同步 数据共享复杂,需要用IPC;数据是分开的,同步简单 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂 各有优势 内存、CPU 占用内存多,切换复杂,CPU利用率低 占用内存少,切换简单,CPU利用率高 线程占优 创建销毁、切换 创建销毁、切换复杂,速度慢 创建销毁、切换简单,速度很快 线程占优 编程、调试 编程简单,调试简单 编程复杂,调试复杂 进程占优 可靠性 进程间不会互相影响 一个线程挂掉将导致整个进程挂掉 进程占优 分布式 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单 适应于多核分布式 进程占优 对比发现线程到底为什么存在的,存在的意义在哪里,我觉得不难发现,多线程的目的就是为了更好地利用多核CPU和内存。我们都知道CPU和内存在计算机领域的意义在高性能应用下的意义,这可谓是挖空心思,因为硬件的局限性我们不得不做出这样复杂的决定,如果我们的计算机硬件有质的飞跃那这些问题可能就不是问题了,我们甚至可以接近光速的速度来计算我们的世界,我们可以在这个宇宙中随心所欲的翱翔,我们可能会创造出一个更加美好的宇宙。 言归正题,实现多线程是要阻塞的,就这一点对于追求高性能来说还是不能容忍。不阻塞那从哪里做起呢,简单说就是从什么地方实现不阻塞的数据类型,哪里性能最高就从哪里开始,哦!!!CPU,对不对,因为任何数据都要在CPU运行。 CAS(cpu 硬件同步原语(compare and swap))(http://baike.baidu.com/link?url=EOQRO_nNRbm68ZsDnxGnU9us0Of8wTBcO03BL-ai5Ux7Hk57QVtQAt0cgohuprKvDvUzSCsAgnIHsnQ7hpHONXAv41zfs7xhBmmeSF9kzwi) 百度出来的,我们可以看出来,它是硬件级别的同步。 Java5之后就有了这些支持,而且不止这些,在多线程领域有了很多优化和性能的提升,几乎是革命性的。不仅提出了更好优雅的实现还有很多更加抽象更加高级的实用的东西,如果都吃透还真是要下大功夫,如果想利用这些做出来高性能的东西出来更是需要长时间的实践和积累。 就在刚才又看了一下disruptor这个东西,其实我也不了解他,也是在前几天偶然的一个视频上看到他,可能是我关注的还不够深入,也许还会有更优秀的东西出来。大致了解了一下发现还是之前我提到的怎么利用CPU、缓存、内存的问题还有CAS和volatile等等吧,可以说在java语言中对于CPU和内存的利用已经做到了很好地支持,而且还屏蔽了操作系统对语言的限制,这才使得java也站在了高性能的制高点上。 有人看到这里可能早已不耐烦了,我也并不打算写一句代码,说实话我实际工作中好没有深入的研究过多线程,甚至连java的多线程api都没有知道多少,我只是不停地看呀看呀,我也不认为我能写出性能特别好的东西来我自知水平能力有限,还好我有一颗学习的心。 最后我还是把握有限搜索到的资料分享出来: http://www.ibm.com/developerworks/cn/java/j-concurrent/ http://blog.csdn.net/column/details/java-thread-.html http://blog.csdn.net/silentmuh/article/details/50501820 http://wenku.baidu.com/link?url=jhjcwqXlXuLb2jPF4bOVJYR26wuIntuZcbJXlD7S3m1C-vNCwf2BTjBdQ8O0dBrmT0yeT8oiEOWdOEVCjyB6S2nkF8BnQTxnOZF0irsRUJ7 期待下一次分享吧。