这篇文章的标题原本叫做——Java 并发编程(一):简介,作者名叫小二。但我在接到投稿时觉得这标题不够新颖,不够吸引读者的眼球,就在发文的时候强行修改了标题(也不咋滴)。

小二是一名 Java 程序员,就职于沉默公司,工龄是两年零一个月零三天。和刚毕业那会相比,编程能力已经大有提升,但领导老王一直没敢把并发编程的开发安排给小二,这让小二心里耿耿于怀。

这事不怪老王,小二心里很清楚:编写正确的程序很难,编写正确的并发程序更是难上加难。自己功力还不到那个份上,万一搞砸了,难免让一向谨慎的老王面上无光。

小二想来想去,办法只有一个,主动去学!就找老王要了一本《Java并发编程实战》,据说这本书是并发编程中的经典之作。拿到书后,随手翻了翻,竟然发现里面藏着一封情书:小二激动坏了,想象着老王写情话的样子,不由得笑出来声。

(戛然而止)

小二的背景就先介绍到这。接下来,我们来一起鉴赏下小二读完这本书后写下的第一篇文章。

Java 并发编程(一):简介

01、为什么需要操作系统

我喜欢在写文章(不用纸和笔用电脑了)的时候听音乐(不用 MP3 用电脑了),假如电脑只能做一件事情的话,我就只能在写完文章的时候再听音乐,或者听完音乐的时候再开始写作,这样就很不爽——在没有操作系统前,的确就是这么不爽。

有了操作系统后,情况就变得大不一样了,电脑可以同时运行多个程序。通过 TOP 命令可以查看电脑上当前正在运行的进程(和程序有着密切的关系),见下图。

通常情况下,一个程序会至少对应一个进程。上图中,“Google Chrome”这三个进程意味着我的电脑上打开着一个名叫谷歌浏览器的程序。

让我们用一段专业的术语来描述一下程序和进程之间的关系:

程序是计算机为完成特定任务所执行的指令序列。 操作系统允许多道程序并发执行共享系统资源,而程序在并发执行时所产生的一系列特点使得传统的程序概念已经不足以对其进行描述,因此,引入了“进程(Process)”:可以更好的描述计算机程序的执行过程,反映操作系统的并发执行、资源共享及用户随机访问的特性,并以此作为资源分配的基本单位。

每当一个程序运行时,操作系统就为该程序创建了一个进程,并为它分配资源、调度其运行。程序执行结束后,进程也就消亡了。一个程序被同时执行多次,系统就会创建多个进程。因此,一个程序可以被多个进程执行,一个进程也可以同时执行多个程序。

当然了,对于现在的操作系统来说,进程并不是最小的调度单位,而是线程。线程也被称为轻量级进程。

由于同一个进程中的所有线程会共享进程的内存地址空间,因此这些线程都能访问相同的变量,如果没有明确的同步机制来协同对共享数据的访问,那么当一个线程正在使用某个变量时,另外一个线程可能同时访问这个变量,就会造成不可预测的结果。

02、多线程的优势

查看了一下,我这台电脑的物理 CPU(处理器)个数只有一个,但是核数(一块 CPU 上面能处理数据的芯片组的数量)是 4 个。

这意味着,我这台电脑能够在同一时间处理一个进程内的四个线程任务:线程 A 正在读取一个文件,线程 B 正在写入一个文件,线程 C 正在计算一个数值,线程 D 正在进行网络传输。

我们知道,进行文件读写或者网络传输通常会发生阻塞,这也是没办法的事。如果没有多线程的帮助,程序会按照顺序依次执行,也就意味着发生阻塞的时候其他任务只能干巴巴的等着,什么也做不了。

有了多线程,情况就完全不一样了,线程之间可以互不干扰,从而发挥处理器的多核能力。

说个有点让人难为情的事,我是 Eclipse 的(愚)忠实用户,至今没切换到 IDEA 阵营。在用 Eclipse 的时候经常会出现这样的情况,一个进度被另外一个卡住,下一个必须等待上一个执行完毕才开始执行。等待的时候几乎什么也干不成,点了取消也没用!

假如 Eclipse 采用多线程的话,每个任务放在单独的任务中执行,响应就会快很多。

03、多线程带来的风险

曾有这样一则耳熟能详的故事。

特洛伊人在城外的海滩上发现了一只巨大的木马,他们把它拉进了城里而不是把它烧掉或推到海里,以为这是天神给特洛伊人带来的赐福。于是,特洛伊人欢天喜地,庆祝胜利,他们跳着唱着,喝光了一桶又一桶的酒,以为希腊人被他们战败了。

而故事的结局大家也都知道了。希腊人把特洛伊城掠夺成空,烧成一片灰烬。海伦(宙斯之女,被称为“世上最美的女人”,她和特洛伊王子私奔,引发了特洛伊战争)也被墨涅依斯带回了希腊。

多线程带来了无与伦比的好处,但也潜藏了巨大的风险(就像那个木马)。其中尤为突出的就是安全性问题。

public class Unsafe {private int chenmo;public int add() {return chenmo++;}
}

上面这段代码在单线程的环境中可以正确执行,但在多线程的环境中则不能。递增运算 chenmo++ 可以拆分为三个操作:读取 chenmo,将 chenmo 加 1,将计算结果赋值给 chenmo。两个线程可能交替执行,发生下图中的情况,于是两个线程就会返回相同的结果。这也是最常见的一种安全性问题。

其次,多线程还会引发活跃性问题:线程 B 需要等待线程 A 释放它们共有的资源,而线程 A 由于一些问题导致无法释放资源,那么线程 B 就只能苦苦地等下去。

再者,多线程还会引发性能问题(设计良好的多线程当然会提高性能):当线程调度器临时挂起一个活跃中的线程转而运行另外一个线程时,就会频繁地出现上下文切换(Context Switch)——开销很大(挣得多花的也多)。

04、单核 CPU 和多核 CPU

来思考一个问题吧。假如 CPU 只有一个,核数也只有一个,多线程还会有优势吗?

闭上眼,让思维旋转跳跃会。

来看答案吧。

单核 CPU 上运行的多线程程序,同一时间只有一个线程在跑,系统帮忙进行线程切换;系统给每个线程分配时间片(大概 10ms)来执行,看起来像是在同时跑,但实际上是每个线程跑一点点就换到其它线程继续跑。所以效率不会有所提高,线程的切换反到增加了系统开销。

那多核 CPU 呢?

当然有优势了!多核需要多线程才能发挥优势(不然巧妇难为无米之炊啊),同样,多线程要在多核上才能有所发挥(好马配好鞍啊)。

多核 CPU 多线程不仅善于处理 IO 密集型的任务(减少阻塞时间),还善于处理计算密集型的任务,比如加密解密、数据压缩解压缩(视频、音频、普通数据等),让每个核心都物尽其用。

05、最后

亲爱的读者朋友们,小二投稿的第一篇文章到此就结束了。你对此感到满意吗?或者说你期待下一篇吗?

(此时的小二正在翘首以盼)


上一篇:Java:并发不易,先学会用

下一篇:如何保证共享变量的原子性?

微信搜索「沉默王二」公众号,关注后回复「免费视频」获取 500G 高质量教学视频(已分门别类)。

Java 并发编程(一):简介相关推荐

  1. Java并发编程实战_[Java并发编程实战] 简介

    并发简史 在早期不包含操作系统的计算机中,程序都是单一的串行程序,从头至尾只能执行一个程序,并且这个程序访问这个计算机的所有资源.然而,随着技术的发展,操作系统出现了.它使得计算机程序有了进程,线程的 ...

  2. [Java并发编程实战] 简介

    并发简史 在早期不包含操作系统的计算机中,程序都是单一的串行程序,从头至尾只能执行一个程序,并且这个程序访问这个计算机的所有资源.然而,随着技术的发展,操作系统出现了.它使得计算机程序有了进程,线程的 ...

  3. 【Java 并发编程】CountDownLatch 简介

    文章目录 I CountDownLatch 概念 II CountDownLatch 使用流程 III CountDownLatch API 简介 I CountDownLatch 概念 1. 概念 ...

  4. java并发编程笔记_java并发编程笔记(一)——并发编程简介

    java并发编程笔记(一)--简介 线程不安全的类示例 public class CountExample1 { // 请求总数 public static int clientTotal = 500 ...

  5. Java并发编程一线程池简介

    推荐:Java并发编程汇总 Java并发编程一线程池简介 为什么我们需要使用线程池? 我们知道线程是一种比较昂贵的资源,我们通过程序每创建一个线程去执行,其实操作系统都会对应地创建一个线程去执行我们的 ...

  6. Java并发编程之介绍

    并发编程简介 将串行执行部分编程并发执行,但要考虑上下文切换和资源调度的时间 并发编程的意义及影响多线程的因素 并发编程的目的是为了让程序运行得更快,但是,并不是启动更多的线程就能让程序最 大限度地并 ...

  7. java 并发编程总结

    这边文章的主要内容是基于"java并发编程艺术"这本书,中间加入了一些自己的理解.这篇文章包括并发编程涉及到的几乎所有基础知识.主要是帮助长期从事业务逻辑开发的java程序员梳理一 ...

  8. Java并发编程面试题(2020最新版)

    转载自  Java并发编程面试题(2020最新版) 基础知识 并发编程的优缺点 为什么要使用并发编程(并发编程的优点) 充分利用多核CPU的计算能力:通过并发编程的形式可以将多核CPU的计算能力发挥到 ...

  9. java并发编程(二十一)----(JUC集合)CopyOnWriteArraySet和ConcurrentSkipListSet介绍

    转载自  java并发编程(二十一)----(JUC集合)CopyOnWriteArraySet和ConcurrentSkipListSet介绍 这一节我们来接着介绍JUC集合:CopyOnWrite ...

  10. Java并发编程(08):Executor线程池框架

    本文源码:GitHub·点这里 || GitEE·点这里 一.Executor框架简介 1.基础简介 Executor系统中,将线程任务提交和任务执行进行了解耦的设计,Executor有各种功能强大的 ...

最新文章

  1. Lucene.Net 2.3.1开发介绍 —— 三、索引(六)
  2. richTextBox1 转到行号
  3. k8s 多租户_k8s使用rbac实现多租户
  4. 蓝桥杯 基础练习 十六进制转八进制
  5. 2018年的AI/ML惊喜及预测19年的走势(一)
  6. 老码农吐血建议:2020年,低于1w的程序员要注意了...
  7. was css,Sass无效的CSS…:期望的表达式(例如,1px,粗体),是“{”
  8. Antechinus C# Editor!
  9. PyTorch 1.0 中文官方教程:使用 Amazon AWS 进行分布式训练
  10. 电子学习资料/电子设计/电子竞赛/产品设计/产品开发(吐血推荐)
  11. 图像处理(四) Sobel边缘检测与canny边缘检测对比
  12. ASEMI整流桥S25VB100,S25VB100参数,S25VB100应用
  13. php视频打水印,php 七牛云 视频加水印
  14. Serverless 极致弹性解构在线游戏行业痛点,你有过迷茫吗
  15. 【墨尘】变态心理学(北京大学)
  16. VUE手写横向轮播图
  17. 人工智能 —— 知识图谱
  18. C端和B端的差异分析
  19. Linux 配置关掉虚拟防火墙
  20. WeiKuCMS多功能微信营销服务系统

热门文章

  1. 红帽Linux自带的光盘刻录,linux下mkisofs制作光盘映像cdrecord刻录光盘
  2. 《解读基金》 基金中统计指标含义-平均回报、标准差、夏普比率、阿尔法系数、贝塔系数、R平方
  3. DeepFool论文翻译---DeepFool: a simple and accurate method to fool deep neural networks
  4. 将指定小程序页面设置为首页的两种方式
  5. Windows Server 2016 (Updated Feb 2018) (x64)下载
  6. [BZOJ3144]切糕
  7. 鸿蒙系统的发展前景,国产系统大有可为!从鸿蒙看未来操作系统的大潮
  8. 易语言取html显示的文本,易语言 获取网页文本
  9. oBlog 4.0 正式版 2006-09-06
  10. 《爱的五种能力》阅读笔记(完整版)