我们一起来聊聊并发吧,one。
引言
最近工作当中写了一个有关并发的程序,引起了LZ对并发的强烈兴趣。这一下一发不可收拾,LZ用了一个多星期,看完了这本共280+页的并发编程书。之所以能看这么快,其实这主要归功于,自己之前对并发就有一定的理解。在这种前提下看书,其实只是一个印证自己之前想法的过程而已,因此看起来会比较快,而且在看的时候,会有多次这种感觉,“擦,原来还真是这样的”。
尽管LZ已经说了看书看的快的原因,但不管怎么说,书看的太快,肯定难免有遗漏。因此博客此时就派上用场了,它绝对可以帮你查缺补漏。因为在写的过程中,你会发现,之前你读的时候自以为理解的透透的东西,却无法给别人讲清楚。这就说明,你需要补补漏了。
并发的来源
并发的由来,从现在来看,似乎是必然的。因为人是一种懒惰而又急躁的动物,这是人的本性。因为急躁,并发就出现了,因为懒惰,多核时代就来了。
为什么这么说呢?
如果所有的程序都是串行的(之所以说如果,是因为LZ接触到电脑时,它已经是并发的了,因此只能想象一下),那么当你打开了一个特别慢的网页,最后你等不及想关掉浏览器的时候,你会发现,你必须等加载这个网页的事做完你才能关闭它。这是何其蛋疼的一件事。急躁的人们能允许这种事发生?因此并发就出现了。
再来想象一下,如果我们想让一个程序运行的更快,从直觉上讲,我们应该让CPU运算的更快。比如以前一秒可以计算1000次,现在我们让它在一秒内可以计算10000次。但是懒惰的人们发现,这种直觉上的方式似乎非常困难,想要硬生生的提高CPU的速度(缩短时钟周期)是非常困难的。因此懒惰的人们就想到一种偷懒的办法,一个CPU一秒可以计算1000次,两个的话不就可以计算2000次了(实际并非如此,但我们可以这么理解多个CPU带来的效率增加),这个相对简单的办法最终被人们采用了。因此多核时代就到来了。
并发的危险
说起并发引起的危险,在LZ的理解来看,主要来源于程序所给人带来的直觉造成的误导。这一点在LZ所写的计算机系统原理中有讲到(可以将这两本书的内容联系起来),比如下面这个程序,它给人的直觉是,a首先变成了1,然后b变成了2。
int a = 1;
int b = 2;
直觉是这样的,但往往是错误的,因为在程序真正执行的时候,可能是b先变成了2,a又变成了1,更奇葩的是,很可能a和b都始终是0。估计说起两者的赋值顺序颠倒,各位还可以理解,但是说到两者可能都是0,有的猿友就懵了,有种瞬间被颠覆三观的感觉,但是学习并发往往就是颠覆你三观的过程。
这种直觉与现实之间的不同,就给并发的程序造成了危险。它可能引起你预料之外的错误,而且往往是防不胜防。因此并发是诱人的,但也同样是危险的,一个诱人的东西永远都伴随着危险,就像高贵的玫瑰往往都是有刺的。
知道了上面这些,我们就可以来看看安全性和活跃性了。安全性是指,“程序不会出现糟糕的事情”,活跃性则是指,“好的事情一定会发生”。可以看出来,安全性更多的是在强调执行的程序是正确的,而活跃性更多的是在强调程序可以正确的往下进行(有点绕?那就对了)。
举个例子,对于一个并发递归求解的程序来讲,安全性则可以保证结果的正确性,而活跃性则可以保证这个程序总能得到一个正确的结果或者最终发现它没有解而抛出无解的异常。
Java的并发
对于大部分从事Java开发不久的程序猿来讲(包括LZ),并发一般都是很少接触到的(这里主要以LZ的领域来说,即J2EE),因为现有的框架已经将很多并发的问题给解决了,并给我们这些无脑程序猿创造了一个串行程序的环境。
比如,在J2EE领域的servlet规范当中,servlet是单例的,并且非常有可能,甚至可以说一定会被多个线程并发的去访问。因此servlet其实是有并发的安全性问题的,除非你不在servlet当中记录任何状态。但是当前比较火的MVC框架struts2已经帮我们解决了这个问题,尽管Action当中经常会有一些数据或者说状态,但Action在struts2中是非单例的,这相当于每个Action实例都是线程私有的,因此不存在并发问题。
有一些情况下,我们可能会接触到并发问题,比如,你需要做一个单例的对象,那么这个对象一般可以被全局访问,因此就可能存在并发的问题。可以这么说,几乎所有采用了单例模式的对象都会涉及到并发的问题,除非这个对象没有任何状态,但是这往往不会出现,因为没有状态的单例对象是没有意义的,它们更好的处理方式应该是一个无实例(即将构造函数私有化)且充满了静态方法的类。
很多程序猿在初次意识到并发时,都会采取一个看似万能却并非一定有用的方法,那就是将一个类的所有方法加上synchronized关键字。LZ以前也是这样的,而且还自认为十分高端,现在想想,LZ实在自惭形秽。当时LZ对synchronized的理解,就知道它可以让很多线程一个一个来执行这个方法,至于其它的特性,就不太明白了。
其实在大部分时候,一些比较简单的场景中,上面这种无脑做法还是能起到相应的作用的,也就是说,它可以保证安全性与活跃性。但是另外一个特性就无法保证了,那就是性能。无脑的方法同步,有时候会将性能降低数个数量级,可能会使很多线程都在等待,CPU却一直处于1%利用率的情况。
通常情况下,对于安全性、活跃性以及性能来说,我们会将性能放在最后一位,引用之前看过的一句经典的话,是用来形容面向对象设计的,即“可复用的前提是可用”。同样的,对于并发的程序来讲,“性能高的前提是程序的执行是正确的”。
小结
今天就暂且写这么多吧,对于并发,其实想说的还有很多,毕竟刚看完这本书。后面还会陆续给出自己的理解,但是会穿插着《计算机系统原理系列》的内容,这个系列也该继续前进了,因为并发已经耽误了它太久。
我们一起来聊聊并发吧,one。的更多相关文章
- 聊聊并发(七)——Java中的阻塞队列
3. 阻塞队列的实现原理 聊聊并发(七)--Java中的阻塞队列 作者 方腾飞 发布于 2013年12月18日 | ArchSummit全球架构师峰会(北京站)2016年12月02-03日举办,了解更 ...
- 聊聊并发-Java中的Copy-On-Write容器
详见: http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp78 聊聊并发-Java中的Copy-On-Write容器 Cop ...
- 聊聊并发(一)深入分析Volatile的实现原理
本文属于作者原创,原文发表于InfoQ:http://www.infoq.com/cn/articles/ftf-java-volatile 引言 在多线程并发编程中synchronized和Vola ...
- 转:聊聊并发(八)——Fork/Join框架介绍
1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过 ...
- 聊聊并发(六)——ConcurrentLinkedQueue的实现原理分析
1. 引言 在并发编程中我们有时候需要使用线程安全的队列.如果我们要实现一个线程安全的队列有两种实现方式:一种是使用阻塞算法,另一种是使用非阻塞算法.使用阻塞算法的队列可以用一个锁(入队和出队用同一把 ...
- 聊聊并发(三)Java线程池的分析和使用
1. 引言 合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要的等到线程创建就能立即执行. ...
- 聊聊并发——深入分析ConcurrentHashMap
术语定义 术语 英文 解释 哈希算法 hash algorithm 是一种将任意内容的输入转换成相同长度输出的加密方式,其输出被称为哈希值. 哈希表 hash table 根据设定的哈希函数H(key ...
- Java并发编程原理与实战一:聊聊并发
一.大纲 •你真的了解并发吗 •多线程和并发 •多线程和多进程 •线程一定快吗 •学习并发的四个阶段 •学习目标 •适合人群 •荐书 二.学习并发的四个阶段 •熟练掌握API,能够完成并发编程 • ...
- 聊聊并发(四)——深入分析ConcurrentHashMap
线程不安全的HashMap 因为多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap,如以下代码 final HashM ...
随机推荐
- 铁乐学python_day21_面向对象编程3
抽象类和接口类 以下内容大部分摘自博客http://www.cnblogs.com/Eva-J/ 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某 ...
- php实现session入库
为什么要把session存入数据库?有什么用? 可以:统计在线人数,现实多站点session共享(通行证),控制同个账号登入人数等. 要实现session的入库,有关键的几个基本知识: session ...
- Oracle创建Rman备份专用账户
有时会因为信息安全需要,创建备份所需的专用账户,不适用sys等用户.可以使用如下方式:create user rman_ycr identified by oracle;grant create se ...
- September 27th 2017 Week 39th Wednesday
We both look up at the same stars, yet we see such different things. 我们仰望同一片星空,却看见了不同的事物. Looking up ...
- ZT 类模板的声明和实现是不能分离的
http://bbs.csdn.net/topics/380250382 adlay adlay 等级: #9 得分:0 回复于: 2012-03-31 11:19:35 引用 6 楼 的回复: 引 ...
- 转贴:C语言链表基本操作
http://www.oschina.net/code/snippet_252667_27314#comments 这个代码有很多错误,估计是从老谭书上抄来但是很多还抄错了:对照老谭的书好好研究下.切 ...
- HTML、jsp页面中radio,checkbox,select数据回显功能,默认被选中问题
最近常常遇到各种复选框.单选框.下拉框的默认被选中的问题,开始也是绞尽脑汁的想办法,今天写一篇学习总结的博文来写一下学习总结. 单选框(radio)默认被选中: 一.jstl技术进行回显 <in ...
- Scala学习——Brief Scala Tutorial
因为Spark项目需要,学习Scala编程. 从官网文档入手:http://www.scala-lang.org/documentation/ 首先从他的Older Documentation入手. ...
- linux 几个常用的Debian更新源
deb http://ftp.debian.org/debian/ lenny main contrib non-free deb-src http://ftp.debian.org/debian/ ...
- 【bzoj2693】jzptab 莫比乌斯反演+线性筛
题目描述 输入 一个正整数T表示数据组数 接下来T行 每行两个正整数 表示N.M 输出 T行 每行一个整数 表示第i组数据的结果 样例输入 1 4 5 样例输出 122 题解 莫比乌斯反演+线性筛 由 ...