NO.001- 简说 Java 并发编程史
这篇文章是Java并发编程思想系列的第一篇,主要从理解Java并发编程历史的原因和Java并发演进过程两部分,以极简地回溯并发编程的历史,帮助大家从历史这个角度去了解一门语言一个特性的演进。对历史理解的越多,思考的越多,未来的方向就会更加坚定。
我是谁?从哪来?到哪去?——柏拉图
一、为什么了解并发编程历史
没有一个新事物一出现就是完美的。回溯Java并发演进的历史,既可以从宏观的角度了解世界上正在发生的变化[知乎],又可以让我们真正的理解当时设计的背后逻辑和历史原因,学习前人决策的智慧,指导我们的工作和生活。然而,Java语言建立在硬件和操作系统之上的,脱离了硬件和操作系统,单单去回溯Java并发历史,则无法看清楚底层的逻辑。
二、并发的演进
2.1 并发的产生
综观计算机历史,操作系统与计算机硬件的发展息息相关[维基]。计算机的发展经历了4个阶段,电子管计算机(1945-1955)、晶体管计算机(1955-1965)、集成电路计算机(1965-1980)、大规模集成电路计算机(1980-至今)。因此,伴随着计算机硬件的更新换代,操作系统也经历了4个阶段,分别是手工操作(50年代早期)、单道批处理系统(50年代)、多道批处理系统(60年代初)、分时系统(60年代中)[操作系统发展历史]。
晶体管的发明后,计算机的可靠性提高了一个层级。由于当时机器非常昂贵,人们期望计算机可以长时间运行[MOS]。单道批处理系统支持把一系列的指令预先写下来,形成一个清单,一次性的交给计算机,这样计算机就可以连续不断读取指令执行相应的操作[海子],通过这种方式提高了计算机的利用率。
然而,由于在单道批处理系统中同时只能执行一个任务,任务在输入输出时,CPU是空闲;反之在计算时,输入输出设备是空闲的。随着集成电路芯片发明和普及,为了更加使用计算机资源,诞生了软件兼容的第三代多道批处理系统,支持多个程序同时进入内存并交替在CPU中运行,共享系统中的软硬件资源。解决了上一代系统一个程序运行时,CPU与外设交替空闲和忙碌的问题,再一次提高了CPU和外设的利用率。

[图摘自:bilibili操作系统的发展和分类]
不过人类对计算机的效率、易用性上的追求上是无止境的,主要体现在两点:
1. 人机交互:对于第三代系统而言,一个程序从提交到运算结果取回往往需要几个小时,有时候会由于一个小错误导致编译失败浪费很多时间,因此用户希望可以独占式的使用计算机,用来调试程序,修改错误。
2. 提高计算机使用效率:当时计算机还十分昂贵,一台计算机需要同时供多个用户共享使用,提高计算机的利用率。
此时,分时操作系统就应运而生了,分时操作系统引入了时间片的概念,把CPU时间按一定的时间间隔,采用轮转运行的方式轮流切换给各个终端用户的程序使用。由于时间间隔很短(linux根据进程的nice值决定如何分配时间片,一般的时间片在ms级别),每个用户就感觉像独占计算机在使用。

[图摘自:bilibili操作系统的发展和分类]
人们为了同时处理多个任务,从第三代多道批处理系统开始,引入了进程。每个进程都对应一块自己的内存空间,不同进程之间互不干扰,同时进程可以保存程序每个时刻的状态,这样就为进程切换提供的可能。从微观角度看同一时刻只有一个进程在使用CPU资源(单核CPU);从宏观角度看有多个任务在同时在执行,这就让并发成为可能[海子]。
2.2 线程的产生
进程提高了CPU的利用率,但是由于一个进程在一个时间段内只能做一件事情,所以存在一些明显的不足:
1. 不支持同一时间进行多个事情:如果想同时干两件事或多件事,进程就无能为力了
2. 进程会被阻塞,无法及时响应:如果进程在执行过程中阻塞了,如等待输入,整个进程就会挂起,无法继续执行。
当然有些人表示,可以把多个事情拆分到多个任务。bingo!这就是线程最初的思想。不过每个进程都会分配单独的内存空间,这种方式会占用更多的资源。所以睿智的前人就想到,能够采用孙悟空的分身术,让同一个进程下的线程共同享有进程占有的资源和地址空间。简单的理解:进程属于在处理器这一层上提供的抽象;线程则属于在进程这个层次上再提供了一层并发的抽象。那么提个问题:线程还可以再细分吗?
2.3 Java并发编程的演进
好啦,铺垫了这么多,终于要说到我们今天的主角,Java的并发编程的历史了。Java并发的演进与计算机系统的演进有着相似性,循着历史的轨迹,我们可以了解到前人是如何在未知的道路上苦苦探索,通过学习前人深邃的思想,来指导我们的工作。

[图摘自:Java并发编程通识]
Java诞生在1990年Sun公司一个内部项目,当时硬件领域出现了价格低廉的单片式计算机系统,使用它可以大幅度提升消费类电子产品(如电视机顶盒、面包烤箱、移动电话等)的智能化程度。Sun公司为了抢占市场先机,在1991年成立了一个称为Green的项目小组,James Gosling等人期望使用一种新语言来解决这类程序跨平台运行问题,于是Java的前身Oak(橡树)语言诞生了。(你看,有很多人抱怨工作挑战太小,无法提升自己,但真正的创新还是要在工作基础上进行延伸)。下图是James Gosling,感谢老爷子养活了这么多java人。

1996年JDK1.0版本发布,Java的目标是write once, run anywhere,由于站在操作系统这个巨人的肩膀上,因此1.0版本就提出了Java语言的内存模型,并确定了线程模型以及实现,如Thread、Runnable。当时Java在语言层面支持了多线程,这是一项非常大胆的创举,但是好事多磨,从1997年就在Java内存模型规范中发现了几处严重的缺陷,这些缺陷造成执行的结果出现混乱,例如:被final修饰的常量值会发生更改,这些缺陷经过了很长一段时间的诟病。
每一次技术的革新总离不开硬件的发展,随着多核架构的出现,虽然Java内存模型改造工程难度之大超出了想象,但是Java 的设计者们还是决定重新修订 Java 的内存模型, 经过了长达 3 年的激烈讨论,时间线来到了2004年9月,JDK1.5发布,并正式更名为5.0(请记住这一个里程碑式的版本吧)。这个版本正式发布了两个重大的规范:JSR133和JSR166。JSR-133规范,即Java内存模型与线程规范。而JSR166的贡献是引入了java.util.concurrent包,提到concurrent包,我想Doug Lea大神大家一定不会陌生。感谢为Java人提供了这么易用的并发工具包。

在推出了JDK5.0后,Java反对的声音越来越少了,但是一个有生命力的语言不会止步于此。随着大规模数据处理的出现,2003年和2004年,Google公司在国际会议上分别发表了两篇关于Google分布式文件系统和MapReduce的论文,公布了Google的GFS和MapReduce的基本原理和主要设计思想。2011年,在JDK7中进一步完善了并发流程控制功能,引入了fork-join框架。
Java从诞生到现在已经有二十年,那么Java 的未来会怎样?我想这新的一页篇章一定有你挥毫书画的风采。

[图摘自:博客园]
三、思想和本质
纵观,计算机和Java并发的演进历程,本质是人类压榨计算机运算能力的历史,也是人类不断探索追求极致性能的历史,而摩尔定律和 Amdahl定律的更替代表了近年来硬件发展从追求处理器频率到追求多核心并行处理的发展过程[深入理解java虚拟机]。
1. Amdahl 定律通过系统中的并行化与串行化的比重来描述多处理器系统能获得的运算加速能力。
2. 摩尔定律则用于描述处理器晶体管数量与运行效率之间的发展关系。
本文作者: 葛一凡
分享是快乐的,也见证了个人成长历程,文章大多都是工作经验总结以及平时学习积累,基于自身认知不足之处在所难免,也请大家指正,共同进步。
注:所有非本人内容均以[]标注,践行原创,践行知识源头,从我做起。
参考
邹恒明. 计算机的心智 操作系统之哲学原理. 机械工业出版社
[荷] Andrew S. Tanenbaum. 现代操作系统[MOS](原书第4版). 机械工业出版社
NO.001- 简说 Java 并发编程史的更多相关文章
- Java并发编程:Thread类的使用
Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...
- 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象
Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...
- Java并发编程深入学习
上周的面试中,被问及了几个并发开发的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,该书内容主要是对ifev ...
- 《Java并发编程实战》/童云兰译【PDF】下载
<Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...
- Java并发编程75道面试题及答案
1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon( ...
- 【转】Java并发编程:Thread类的使用
一.线程的状态 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于对Thread类中的方法的理解. 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以 ...
- Java并发编程快速学习
上周的面试中,被问及了几个关于Java并发编程的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,学习后的体会 ...
- Java并发编程73道面试题及答案 —— 面试稳了
今天主要整理一下 Java 并发编程在面试中的常见问题,希望对需要的读者有用. 1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任 ...
- 3、Java并发编程:Thread类的使用
Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...
随机推荐
- 如何在FL Studio中使用自动剪辑(下)
在上集中我想大家介绍了FL Stduio Automation Clip的创建.播放列表操作及包络线类型介绍,在这篇文章中我将会给大家介绍如何在播放列表中使用Automation,剪辑通道的操作及使用 ...
- 工作中使用mongodb
写了一个mongodb的基类 1 <?php 2 3 namespace BI\Service\MongoDB; 4 5 use MongoDB\Driver\BulkWrite; 6 use ...
- 【Vue】VUE源码中的一些工具函数
Vue源码-工具方法 /* */ //Object.freeze()阻止修改现有属性的特性和值,并阻止添加新属性. var emptyObject = Object.freeze({}); // th ...
- Eclipse中get/set方法自动生成
代码中点击右键(快捷键Ctrl+Alt+S) ->Source ->Generate Getters and Setters... ->全选(或选择需要生成的字段/方法) 动图: 静 ...
- 我是如何使计算提速>150倍的
我是如何使计算提速>150倍的 我的原始文档:https://www.yuque.com/lart/blog/lwgt38 书接上文<我是如何使计算时间提速25.6倍>. 上篇文章提 ...
- Centos7 之间的文件拷贝
环境: 内网了两台cenots7主机 scp命令 scp [参数] [原路径] [目标路径] scp -P 22022 /home/file.war root@192.168.253.172:/hom ...
- Moviepy音视频开发:视频转gif动画或jpg图片exe图形化工具开发案例
☞ ░ 前往老猿Python博文目录 ░ 一.引言 老猿之所以学习和研究Moviepy的使用,是因为需要一个将视频转成动画的工具,当时在网上到处搜索查找免费使用工具,结果找了很多自称免费的工具,但转完 ...
- 老猿学5G专栏完结说明
老猿学5G是因为工作原因促成的,主要目的是为了研究5G的计费架构相关内容,到今天为止,基本上达成目标,因此这个专栏基本上告一段落了. 回想这2个多月的日子,从一个对5G相关知识完全不熟悉的小白,到现在 ...
- 第5.2节 Python的函数参数收集
函数的参数使用除了常规的位置参数和关键字参数外,还支持可变个数的函数参数,这种支持可变个数的参数方法称为参数收集,对应的参数称为收集参数. 一.参数收集的定义 Python的函数支持可变不定数量的参数 ...
- 第十七章、Model/View开发:QListView的功能及属性
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 QListView是从QAbstractItemView 派生的类,实现了QAbstrac ...