并发指在宏观上的同一时间内同时执行多个任务。为了满足这一需求,现代的操作系统都抽象出 线程 的概念,供上层应用使用。

这篇博文不打算详细展开分析,而是对java并发中的概念和工具做一个梳理。
沿着并发模型、并发要解决的问题、基本工具、衍生工具这一思路展开。

<!-- more -->

线程

首先线程是什么?线程是由OS抽象并实现的,我们知道OS的职责是管理并合理分配硬件资源,那么OS为了更好的管理、分配CPU资源,同时也为了满足同时执行任务这一需求,设计了线程这一概念。

虽然java程序运行在JVM虚拟机上,但是java的线程仍然是对操作系统原生线程的封装,同时,jvm对线程实现时也将jvm的运行栈设计成线程私有内存,因此,java线程和原生线程在理解上实际上没太大区别。

线程的五种状态:

graph LR
新建 --> 就绪;
就绪 --> 运行;
运行 --> 就绪;
运行 --> 阻塞;
阻塞 --> 就绪;
运行 --> 死亡;

先来看上面的就绪状态和运行状态。我们知道线程虽然宏观上是同时执行的,但是微观上使用如时间片轮转算法使得线程依次执行。那么,同一时间只有一个线程执行,其它需要执行的线程处于 就绪队列 中,等待自己被调度到。

而如果线程想要暂时放弃在CPU上运行的权利,就会阻塞自己。这时对应着阻塞状态,同时线程会从就绪队列中移除,进入等待队列。
很显然,阻塞线程被唤醒肯定是进入就绪队列等待调度,而不可能是直接分配到CPU上运行。

在线程同步时,线程可能由于以下情况被阻塞:

  1. 同步阻塞。就是被锁阻塞。
  2. 等待阻塞。被条件变量阻塞。
  3. 其它。调用sleep(), join()或等待IO操作时的阻塞。

并发需要解决的问题

功能性问题

线程同步面临两个问题,想象下有两个线程在协作工作完成某项任务。那么需要解决以下问题:

  1. 线程两个线程之间交互数据,必然涉及到数据共享。而某些数据资源无法被多个线程同时使用(临界区),这时需要,即线程互斥问题。
  2. 假如一个线程进行的太快,另外一个线程就需要等等它,即线程同步问题。

性能和可用性问题

在多线程程序的性能问题上,如果是对于同样一段临界区的多线程访问,那么则有以下几个思路:

  1. 互斥锁。互斥锁即保证同一时间只有一个线程访问临界区并完整执行完,其它线程在临界区外面等待。
  2. 无障碍或无锁。线程们一开始直接进入临界区执行,注意其中不能修改共享数据。执行完后再判断刚才这段时间是否有其它线程执行,没有的话才修改共享数据,如果有的话就回滚重来。
  3. 降低锁粒度。也即将这个大的临界区拆分成几个小的临界区,分别加互斥锁控制,这样提高了线程同时访问的临界区的机会变多,性能提高。显然这要对代码仔细推敲,考虑如何拆分锁粒度而不影响整体的语义。

以上三种思路的性能优劣没有一个普适的结果,和具体的场景相关。

并发中还会出现以下几种情况导致系统不可用:

  1. 死锁。不解释。
  2. 饥饿。线程调度算法如果不是平等分配的,那么就可能出现优先级高的线程长时间占用CPU,导致优先级低的线程无法得到执行机会。
  3. 活锁。这个我解释不来。。。

并发代码的几个性质

并发编程中需要考虑的几个概念:

  1. 原子性:指某个操作一旦被某个线程执行,直到该操作执行完毕都不会有其它线程来干扰。
  2. 可见性:指某个变量或某块内存如果被A线程修改,B线程能否马上读取到修改后的值。
  3. 有序性:A线程执行的代码序列,在B线程看来是否是有序的。

从我个人的理解来看,原子性属于由并发和线程这一理论概念自然而然推导衍生而来的概念,而可见性和有序性是具体的工程实践中产生的。
实际中,jvm并不能实现的特别完美,总会有工程上的妥协。理论模型与实际模型无法完美契合,总存在一定的偏差。
比如说,jvm为了向性能妥协使用了缓存机制,牺牲了数据一致性,这就产生了可见性的概念,需要程序员编程时自己控制。
jvm为了指令更高效率的执行进行了指令重排优化,则产生了有序性的问题。印象里以前大学里学过的CPU的流水线技术,为了指令能够更好的被CPU流水线利用,减少流水线的空闲时间,编译器编译时也会在不影响 串行语义 的前提下,进行指令重排。
总而言之,这是在性能和理论模型完整性之间的一种妥协。

并发的工具

技术上的工具、概念繁多复杂,但是如果我们能理解技术设计上无时无刻的不运用抽象和分层的手段,
那么,我们可以把技术上的工具分为两种:

  1. 最基本的、原生的工具。
  2. 在原生提供的工具上,进行封装得到的更高层次的工具。

更高层次的工具对基础工具进行了抽象和封装,屏蔽了其中的实现细节。
这里想强调的是,工具的接口实现是分开的,两者可以没有关系。
如java的监视器锁从接口上来看,其语义和互斥锁一样。然而它并不一定使用互斥锁实现,而是可以为了性能存在优化,只要最终的行为与接口相同即可。

基本工具

锁、条件变量、信号量

有三种用于线程同步的工具:

  1. 锁。锁可用于规定一个 临界区,同一时间临界区内仅能由一个线程访问。其他线程则在临界区外等待(阻塞)。
  • 互斥锁。使用信号量实现。临界区外等待的线程会被阻塞。
  • 自旋锁。临界区外等待的线程会忙等。
  1. 条件变量(Condition)。线程在某种条件不满足时阻塞自己,等待其它的线程条件满足时再唤醒它们。很显然所有等待的线程要放入一个数据结构中,这个数据结构就在条件变量内。
  2. 信号量。操作系统原生的机制。实际上,锁 + 条件变量可完成所有信号量可以完成的逻辑。

在java中,Object类有wait()、notify()和notifyAll()之类的方法。
这些方法可以认为每个对象都内置了一个条件变量,而这些方法是对这些条件变量的操作,因此,可以使用这些方法将对象当作条件变量使用,从而做到线程的同步。

为了让学习变得轻松、高效,今天给大家免费分享一套Java入门教学资源。帮助大家在成为Java架构师的道路上披荆斩棘。需要资料的欢迎加入学习交流群:9285,05736

谈一谈Java编程开发中的并发控制相关推荐

  1. 谈一谈Java编程开发中虚拟机的内存区域划分?猿们怎么看?

    java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,有的区域随虚拟机进程的启动而存在,有的区域则依赖线程而存在.包括以下几个运行时数据区域: 程序计数器(线程私有): ...

  2. Java编程开发中高效编码的7个技巧?你应该知道……

    1. 使用 JDK 8 或更高版本 从 JDK 8 以及 更高版本开始,引进许多新功能将允许你编写更短.更具表现力的代码,包括 lambda 表达式.functional 接口.stream API等 ...

  3. java vector编程_Java编程开发中向量(Vector)及其应用

    要学习Java编程开发中向量及其应用方面的知识就要先了解什么是向量,向量是如何声明及初始化的,下面就让IT培训网专家来给大家详细介绍下如何认识向量及其使用方法吧! 关于向量的介绍: 向量 vector ...

  4. java面向字符的输入流_Java编程开发中面向字节的输入输出流

    关于面向字符的输入流和输出流方面教程已经讲解完了,下面要介绍的就是Java编程开发中面向字节的输入输出流,希望本节内容可以帮助大家更好的学习Java. 教程回顾点击查看: 字节流以字节为传输单位,用来 ...

  5. Anders Hejlsberg谈C#、Java和C++中的泛型

    Anders Hejlsberg谈C#.Java和C++中的泛型 [翻译] lover_P 2004-03-25 ------------------------------------------- ...

  6. 小学教育如何利用计算机思维,浅谈如何在中小学编程教学中培养学生的计算思维...

    浅谈如何在中小学编程教学中培养学生的计算思维 伍成伟 四川省 泸县二中城西学校 四川 泸州 646100 摘要:思维是人类所具有的高级认识活动,思维是人对外界输入信息与脑内储存知识经验进行一系列复杂的 ...

  7. 你了解Java应用开发中的注入攻击吗?

    第31讲 | 你了解Java应用开发中的注入攻击吗? 安全是软件开发领域永远的主题之一,随着新技术浪潮的兴起,安全的重要性愈发凸显出来,对于金融等行业,甚至可以说安全是企业的生命线.不论是移动设备.普 ...

  8. JAVA 编程中的汉字处理(1)---java 编程技术中汉子问题的分析与解决

    Java 编程技术中汉字问题的分析及解决 段明辉, 自由撰稿人 简介: 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题.一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够 ...

  9. java 静态代码块有什么用,java编程开发静态代码块的使用方法都有哪些

    代码块是程序员在学习java编程开发的时候会接触到的一个代码,而今天我们就通过案例分析来了解一下,java编程开发静态代码块的使用方法都有哪些. (一)java静态代码块静态方法区别 一般情况下,如果 ...

最新文章

  1. Silverlight初级教程-开发工具
  2. 推断给定的IP地址是否是内网IP
  3. pytorch处理多维输入的问题
  4. 真强啊!建议每一位Java程序员都读读Dubbo心跳设计的源码...
  5. racte margin 居中 失效_上干货,微信用情侣签名她肯定很开心,微信个性签名居中隐藏技巧...
  6. JZOJ__Day 4:【普及模拟】游戏
  7. 互联网话题: 陈冠希, 张柏芝, 台湾, ASP与雪灾
  8. Mysql5.7 ZIP 压缩包非安装版的安装方式
  9. Android json数据解析及简单例子
  10. 【clickhouse】未解决 ClickHouse exception, code: 1002 DB::Exception: Directory already exists
  11. 一个经典约瑟夫问题的分析与解答
  12. Python线程池(thread pool)创建及使用+实例代码
  13. SaaSpace:12种最好的免费甘特图软件工具
  14. Ant Design Vue - 修改<Table>表格组件默认的暂无数据图标(自定义表格空数据状态图片)
  15. 怎么学计算机中级,计算机二级自学要多久 怎样复习
  16. 一文学会快速傅里叶变换(FFT)
  17. python手机app签到_Python实现App自动签到领取积分功能
  18. 融金所-孙明达:中国普惠金融覆盖率已属较高水平
  19. iOS 使用oc 版本的Lottie 库
  20. Matlab/simulink采样仿真数据(时序)和时间序列的保存

热门文章

  1. 数据结构——线性表的C语言实现
  2. 数据库基础知识——MySQL服务的启动和停止
  3. C语言int r(int m),INT(M)表示什么意思?
  4. ajax官方api,yangguozhong
  5. html异形轮播,异形滚动
  6. Windows下安装Tensorflow
  7. 工业机器人国内外的发展现状
  8. python asyncio 异步编程-协程 2
  9. HTTP状态码表格汇总
  10. ThinkPHP入门