1 学习多线程知识的根本目标

多线程知识的根本目标是:设计稳健的并发程序。

当然,本文无法回答这个实践性很强的问题(这与具体的业务相关,涉及到具体的策略),本文主要阐述相关知识之间的关系,希望初学者不要迷失在多线程工具类的API接口中。

2 并发程序的三大宏观问题

线程安全性问题、性能问题、活跃性问题。 三者的关系是,在设计并发程序过程中要首先保证线程安全,在线程安全的基础上努力提升程序性能,在保证线程安全与提升性能时避免引入活跃性问题。

线程安全是最重要的,设计并发程序是为了提升程序的性能,但是永远不要忘记性能是建立在安全的基础上的;而在保证安全性(如加锁、同步等方法)及优化并发性能(如通过锁分解、锁分段等方法)过程中,可能会引入活跃性问题(如死锁、饥饿、活锁、糟糕的响应性等问题)。 本文主要阐述线程安全问题的知识。

3 线程安全性

3.1 线程安全性的定义

当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么就称这个类是线程安全的。最核心的概念就是正确性。正确性的含义是,某个类的行为与其规范完全一致。

就像你要设计一道菜,那么组成这道菜的食材和调料一定是可控的,即你能确切的描述对这些食材和调料操作的结果,比如放油菜会香,放盐菜会咸,并且知道菜快熟时再放盐,只有对构成这道菜的所有元素都清楚明晰,设计出的菜才符合设想。设计程序时也一样,只有使用的各个变量和函数是可控的,设计出的程序才能按照设计运行。而多线程的使用,可能会使得组成程序的某些变量和行为变得不可控。

3.2 为什么多线程会带来线程安全性问题

要阐明线程安全性问题需要深入到JAVA内存模型,这里暂时不引入,这里用两个生活中的例子来阐述线程安全性问题的本质(原子性问题和可见性问题)。

【例1】以炒菜为例。其中有个操作是放盐,放盐的操作可分解为三个步骤“找到盐罐→检查盐罐装的是盐→菜快熟的时候将盐倒入菜中”。如果只有一个人在使用盐罐,那么不会有什么问题。但是,如果在你“检查盐罐中装的是盐”之后,将盐倒入菜中之前,另一个人拿走了盐罐,装了三氯氰胺奶粉,然后将盐罐放回。这个调换过程你并不知道,最后你将调换过的三氯氰胺奶粉倒入了菜中,结果可想而知。这就是线程安全性问题的原子性问题。

从内存模型理解原子性问题:juejin.im/post/684490…

【例2】以A和B协作煮米饭为例。有三个房间(厨房、控火室、观察室),厨房有个锅煮着米饭(锅上有张纸写着“已熟”或者“未熟”),A在控火室负责关火(当看到锅上的纸写着“已熟”时关火),B在观察室负责观察米的状态并修改锅上贴纸的状态字(已熟/未熟);A和B不在一个房间,无法直接交流;B隔一会观察下锅里的米,如果米熟了就在一张纸上写“已熟”,未熟就写“未熟”,B很忙,写完字后将纸贴在了自己门上,未贴在厨房的锅上。最终结果是,A看到锅上的状态字一直是“未熟”,所以不关火,最终米饭糊了。这就是可见性问题。

从内存模型理解可见性问题:juejin.im/post/684490…

3.3 解决原子性问题和内存可见性的核心

要编写线程安全的代码,其核心在于要对状态(变量)访问操作进行管理,特别是对共享的和可变的状态的访问。

共享意味着可由多个线程访问操作,可变意味着可以被修改。

上述例1中,如果盐罐不共享即其他人不能使用,则不会有线程安全性问题。如果规定不能往盐罐中装入,只能从盐罐中取出,那么不管多少个人可以操作盐罐,盐罐中始终是盐,没有线程安全性问题;同样,如果一个变量不能被修改,那么不管多少个线程操作这个变量,也不会带来线程安全性问题。

上述例2中,如果强制B在修改状态字后,将纸贴在锅上,那么就可以让A看到米饭的真正状态,就可以及时关掉火,蒸出香喷喷的米饭。

那么,为了解决原子性问题和内存可见性问题,怎么对共享的且可变的变量进行管理?

除非需要某个域是可变的,否则应将其声明为final域(即声明为不可变的)

将对共享变量的并行操作转换为串行操作(如同步机制、将变量委托给同步容器进行管理)

将共享变量转换为不共享变量(如线程封闭(栈封闭、ThreadLocal类等))

如果某个操作需要以原子方式执行,那么就想办法保证这个操作是原子方式执行(如给操作加锁)

对于需要保证内存可见性的变量,可以强制线程从主内存而不是缓存中读取变量,在线程存储变量时强制存取到主内存中。(如加锁,声明volatile变量)

切记,核心是管理共享的可变状态,锁(内置锁、Lock锁)、同步容器类(Vector、Hashtable等)、并发容器类(ConcurrentHashMap、CopyOnWriteArrayList)、同步工具类(闭锁、信号量、栅栏)、线程池等都只是是管理共享的可变状态的工具。

java线程知识梳理_Java多线程——多线程相关知识的逻辑关系梳理相关推荐

  1. java线程不能重复_Java中多线程重复启动

    标签: 在面试时候经常被问到多线程的相关问题: 今天在测试的时候发现下面的代码会抛出异常: java.lang.IllegalThreadStateException public static vo ...

  2. java 线程 状态 图_Java提高——多线程(一)状态图

    操作系统中的进程和线程的概念 进程是指一个内存运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程,比如windows下的一个运行的应用程序.exe就是一个进程. 线程是指进 ...

  3. java线程的优点_Java使用多线程的优势

    Java使用多线程的优势 如果使用得当,线程可以有效地降低程序的开发和维护等成本,同时提升复杂应用程序的性能.那么Java使用多线程的优势具体有哪些呢,一起来了解一下! 1.发挥多处理器的强大能力 现 ...

  4. Java中常见RuntimeException与其他异常表及Exception逻辑关系详解

    Java中常见RuntimeException与其他异常表及Exception逻辑关系详解 前言 常见`RuntimeException` 其他错误类型 `Error`类 `Exception`类 E ...

  5. java 线程面试题_JAVA多线程面试题(一)

    1.进程和线程的区别 一个进程是一个独立(self contained)的运行环境,它可以被看作一个程序或者一个应用.而线程是在进程中执行的一个任务.Java运行环境是一个包含了不同的类和程序的单一进 ...

  6. java 线程池 分组_JAVA面试题解惑系列(十)——话说多线程

    线程或者说多线程,是我们处理多任务的强大工具.线程和进程是不同的,每个进程都是一个独立运行的程序,拥有自己的变量,且不同进程间的变量不能共享:而线程是运行在进程内部的,每个正在运行的进程至少有一个线程 ...

  7. java线程安全例子_Java总结篇系列:Java多线程(三)

    本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 1 public classThreadTest {2 3 public static voi ...

  8. java线程 cpu占用率_多线程程序 怎样查看每个线程的cpu占用

    可以用下面的命令将 cpu 占用率高的线程找出来: ps H -eo user,pid,ppid,tid,time,%cpu,cmd --sort=%cpu 这个命令首先指定参数'H',显示线程相关的 ...

  9. java线程实例题_java线程相关试题实例源码代码

    java线程相关试题实例源码代码. /** * 计算输出其他线程锁计算的数据 */ class ThreadA { public static void main(String[] args) { T ...

最新文章

  1. as3 android白屏,Android 8.0中一些坑以及对应的解决方法
  2. Java的scjp_java scjp
  3. HTML5 网站大观:12个优秀的 HTML5 黑色风格网站设计
  4. spring + redis 实现数据的缓存
  5. hdu 3065 AC自动机
  6. 主机挂载存储_备战CKA每日一题——第3天 | 对接CSI存储知识
  7. java post webservice_[java.webservice] 如何通过HttpPost从服务器上获得一个sessionid
  8. Java程序员---技能树
  9. python数据参数_零基础学习python数据分析——函数的参数
  10. jstack命令分析
  11. hdu 4417 树状数组查询区间不是1到n时需要转换,例[0,5]变成[1,6]
  12. Armadillo:踩坑指南(ubuntu-16.04+clion)
  13. UltraEdit编辑器中文乱码问题解决
  14. CalBioreagents 绵羊抗α-2-HS糖蛋白 亲和纯化说明
  15. 2021杭州电子科技大学计算机考研,2021杭州电子科技大学研究生拟录取名单公布(一志愿)...
  16. JAVA+=运算程序诡异事件
  17. 在IPCAM上实现RTSP协议直播-live555
  18. 水印去除(基于nosie2noise优化 代码+模型)
  19. java 23种设计模式详解
  20. 迷宫求解【穷举求解法】

热门文章

  1. wps出现安装installer_为什么不能安装WPS
  2. mysql password no_mysql 连接问题(using password: NO)
  3. 15年3月c语言试卷,2015年3月二级C语言新增无纸化真题试卷(三)
  4. adas功能受限_高级驾驶辅助系统(ADAS)的主要功能有哪些?
  5. java并发编程核心方法与框架_Java并发编程核心方法与框架-Future和Callable的使用...
  6. 8idmp导入oracle 11g,11g导入8i的dmp文件问题
  7. 『ACM-算法-Hash算法』信息竞赛进阶指南--字符串哈希
  8. QT 文字字体和颜色设置
  9. [Golang] GoConvey测试框架使用指南
  10. Python模块:time模块详解(转)