这篇文章是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. 摩尔定律则用于描述处理器晶体管数量与运行效率之间的发展关系。

本文作者: 葛一凡

分享是快乐的,也见证了个人成长历程,文章大多都是工作经验总结以及平时学习积累,基于自身认知不足之处在所难免,也请大家指正,共同进步。

注:所有非本人内容均以[]标注,践行原创,践行知识源头,从我做起。

参考


  1. Java 多线程发展简史 | 四火的唠叨

  2. Java并发编程:进程和线程之由来 - Matrix海子 - 博客园

  3. 操作系统发展历史 - 云+社区 - 腾讯云

  4. 2019 王道考研 操作系统_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili

  5. 有了进程为什么还要线程?_tongxinhaonan的专栏-CSDN博客

  6. Java并发编程之线程篇之线程的由来(一) | AndyJennifer’Blog

  7. Java并发编程通识 - 罗辑思维技术博客

  8. Java 并发:并发背景_Rico’s Blogs-CSDN博客

  9. JSR 133 (Java Memory Model) FAQ

  10. Java 内存模型深入分析 - 链闻 ChainNews

  11. 邹恒明. 计算机的心智 操作系统之哲学原理. 机械工业出版社

  12. [荷] Andrew S. Tanenbaum. 现代操作系统[MOS](原书第4版). 机械工业出版社

  13. 论文:The Java Memory Model: a Formal Explanatio

NO.001- 简说 Java 并发编程史的更多相关文章

  1. Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

  2. 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象

    Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...

  3. Java并发编程深入学习

    上周的面试中,被问及了几个并发开发的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,该书内容主要是对ifev ...

  4. 《Java并发编程实战》/童云兰译【PDF】下载

    <Java并发编程实战>/童云兰译[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062521 内容简介 本书深入浅出地介绍了Jav ...

  5. Java并发编程75道面试题及答案

    1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon( ...

  6. 【转】Java并发编程:Thread类的使用

    一.线程的状态 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于对Thread类中的方法的理解. 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以 ...

  7. Java并发编程快速学习

    上周的面试中,被问及了几个关于Java并发编程的问题,自己回答的都不是很系统和全面,可以说是"头皮发麻",哈哈.因此果断购入<Java并发编程的艺术>一书,学习后的体会 ...

  8. Java并发编程73道面试题及答案 —— 面试稳了

    今天主要整理一下 Java 并发编程在面试中的常见问题,希望对需要的读者有用. 1.在java中守护线程和本地线程区别? java中的线程分为两种:守护线程(Daemon)和用户线程(User). 任 ...

  9. 3、Java并发编程:Thread类的使用

    Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...

随机推荐

  1. 攻克solo第六课(大调音阶与真的爱你)

    在本期文章中,笔者将通过guitar pro7和大家分享大调音阶的知识. 不知道大家有没有试着使用my song book里面的谱子,反正笔者是觉得赚大了,并且找了囊括民谣.爵士到摇滚在内不同风格的谱 ...

  2. 「LOJ 3153」 「JOI Open 2019」三级跳

    题面 LOJ 3153 solution 对于任意一对\(A,B\),若区间\([A,B]\)中存在一个数权值大于\(A\)或\(B\),则用这个数来替代\(A\)或\(B\)显然更优. 故只需要考虑 ...

  3. linux命令模式配置安装mysql

    系统环境: centos 7.1 使用模式:命令模式 使用工具:xshell5 . xftp5 安装mysql前必须删除干净旧的安装包和残留文件,否则安装会失败 查看旧的安装包 rpm -qa | g ...

  4. Java基础教程——Map

    Map 返回类型 方法 描述 V get(Object key) 根据key取得value V put(Obejct k,Object v) 向Map中加入(替换)元素,返回之前的Value:之前没有 ...

  5. 超稳攻略!Rancher 2.3手动轮换证书,保护集群安全!

    本文转自Rancher Labs 前 言 Rancher 2.3正式发布已经一年,第一批使用Rancher 2.3的用户可能会遇到Rancher Server证书过期,但是没有自动轮换的情况.这会导致 ...

  6. web.xml之servlet与filter配置

    servlet配置 一个完整的servlet配置分为两块,< servlet >块和< servlet-mapping >块 < servlet > <ser ...

  7. 2、Spring Cloud和dubbo简介

    1.Spring Cloud简介 (1).Spring Cloud简介 SpringCloud,基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负 ...

  8. 赶紧收藏吧!MyBatis-Plus万字长文图解笔记,错过了这个村可就没这个店了

    简介 MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发.提高效率而生 愿景 我们的愿景是成为 MyBatis 最好的搭档 ...

  9. c++如何按照map的value进行排序?

    static bool cmp(pair<char, int> a , pair<char,int> b) { return a.second>b.second; //按 ...

  10. zookeeper未授权访问渗透测试及修复方法

    zookeeper未授权访问危害 服务器信息泄露.集群被破坏 一. 四字命令未授权使用 1.1 测试 工具:netcat ,Linux或Windows都可以测 命令行输入echo envi | nc ...