作者:a60782885

blog.csdn.net/a60782885/article/details/77803757

注,本篇只是解析基本概念,用作面试应答,非深入

对于Java并发编程,一般来说有以下的关注点:

  1. 线程安全性,正确性。

  2. 线程的活跃性(死锁,活锁)

  3. 性能

其中线程的安全性问题是首要解决的问题,线程不安全,运行出来的结果和预期不一致,那就连基本要求都没达到了。

保证线程的安全性问题,本质上就是保证线程同步,实际上就是线程之间的通信问题。我们知道,在操作系统中线程通信有以下几种方式:

  1. 信号量

  2. 信号

  3. 管道

  4. 共享内存

  5. 消息队列

  6. socket

java中线程通信主要使用共享内存的方式。共享内存的通信方式首先要关注的就是可见性和有序性。而原子性操作一般都是必要的,所以主要关注这三个问题。

1.原子性

原子性是指操作是不可分的。其表现在于对于共享变量的某些操作,应该是不可分的,必须连续完成。例如a++,对于共享变量a的操作,实际上会执行三个步骤:

  1. 读取变量a的值

  2. a的值+1

  3. 将值赋予变量a 。

这三个操作中任何一个操作过程中,a的值被人篡改,那么都会出现我们不希望出现的结果。所以我们必须保证这是原子性的。Java中的锁的机制解决了原子性的问题。

2.可见性

可见性是值一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的。

为什么会出现这种问题呢?

我们知道,java线程通信是通过共享内存的方式进行通信的,而我们又知道,为了加快执行的速度,线程一般是不会直接操作内存的,而是操作缓存。

java线程内存模型:

实际上,线程操作的是自己的工作内存,而不会直接操作主内存。如果线程对变量的操作没有刷写会主内存的话,仅仅改变了自己的工作内存的变量的副本,那么对于其他线程来说是不可见的。而如果另一个变量没有读取主内存中的新的值,而是使用旧的值的话,同样的也可以列为不可见。

对于jvm来说,主内存是所有线程共享的java堆,而工作内存中的共享变量的副本是从主内存拷贝过去的,是线程私有的局部变量,位于java栈中。

那么我们怎么知道什么时候工作内存的变量会刷写到主内存当中呢?

这就涉及到java的happens-before关系了。

在JMM中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。

这个人的博客写的不错:http://ifeve.com/easy-happens-before/。

简单来说,只要满足了happens-before关系,那么他们就是可见的。

例如:

线程A中执行i=1,线程B中执行j=i。如果线程A的操作和线程B的操作满足happens-before关系,那么j就一定等于1,否则j的值就是不确定的。

happens-before关系如下:

  1. 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

  2. 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;

  3. volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

  4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

  5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

  6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

  7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

  8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

从上面的happens-before规则,显然,一般只需要使用volatile关键字,或者使用锁的机制,就能实现内存的可见性了。

3.有序性

有序性是指程序在执行的时候,程序的代码执行顺序和语句的顺序是一致的。

为什么会出现不一致的情况呢?

这是由于重排序的缘故。

在Java内存模型中,允许编译器和处理器对指令进行重排序,但是重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。

举个例子:

线程A:

context = loadContext();    inited = true;    

线程B:

while(!inited ){ sleep}doSomethingwithconfig(context);

如果线程A发生了重排序:

inited = true;    context = loadContext(); 

那么线程B就会拿到一个未初始化的content去配置,从而引起错误。

因为这个重排序对于线程A来说是不会影响线程A的正确性的,而如果loadContext()方法被阻塞了,为了增加Cpu的利用率,这个重排序是可能的。

如果要防止重排序,需要使用volatile关键字,volatile关键字可以保证变量的操作是不会被重排序的。

如有文章对你有帮助,

“在看”和转发是对我最大的支持

关注Java开发宝典

每天学习Java技术

点赞是最大的支持 

treemap怎么保证有序_你对多线程熟悉吗,谈谈线程安全中的原子性,有序性和可见性?...相关推荐

  1. treemap怎么保证有序_干货!208道面试题教你怎么通过面试!

    [如您对本文感兴趣,请点击标题下方蓝色"拓达IT训练营"添加关注,每天都有精彩实用文章呈现给您] 一.Java 基础 1.JDK 和 JRE 有什么区别? 2.== 和 equal ...

  2. 面试官:你对多线程熟悉吗,谈谈线程安全中的原子性,有序性和可见性?

    作者:a60782885 blog.csdn.net/a60782885/article/details/77803757 注,本篇只是解析基本概念,用作面试应答,非深入 对于Java并发编程,一般来 ...

  3. python多线程_【python多线程02】各种线程锁

    0x00 前言 本片文章讲述了小明同学在编写python多线程过程中遇到一些奇怪现象,小明根据这些奇怪现象挖掘背后的原因...通过遇到的问题,引申出全局解释器锁,同步锁,递归锁,信号量... 0x01 ...

  4. Android多线程研究(8)——Java中的原子性理解

    一.什么是原子性 原子性是世界上最小单位,具有不可分割性.比如a=0;(a非long和double类型)这个操作是不可分割的,那么我们说这个操作是原子操作.再比如:a++;这个操作实际上是a=a+1; ...

  5. java 线程的构造函数_[c++11]多线程编程(二)——理解线程类的构造函数

    构造函数的参数 std::thread类的构造函数是使用可变参数模板实现的,也就是说,可以传递任意个参数,第一个参数是线程的入口函数,而后面的若干个参数是该函数的参数. 第一参数的类型并不是c语言中的 ...

  6. 多线程怎么保证数据安全_「软帝学院」Java挑战者专栏:多线程详解2

    软帝学院笔记Day21 多线程(单例设计模式)(掌握) 单例设计模式:保证类在内存中只有一个对象. 如何保证类在内存中只有一个对象呢? (1)控制类的创建,不让其他类来创建本类的对象.private ...

  7. java并发框架支持锁包括,tip/面试题_并发与多线程.md at master · 171437912/tip · GitHub...

    01. java用()机制实现了进程之间的同步执行 A. 监视器 B. 虚拟机 C. 多个CPU D. 异步调用 正解: A 解析: 监视器机制即锁机制 02. 线程安全的map在JDK 1.5及其更 ...

  8. ios查看线程数量_关于iOS多线程,你看我就够了(已更新)

    作者:@翁呀伟呀 授权本站转载. 在这篇文章中,我将为你整理一下 iOS 开发中几种多线程方案,以及其使用方法和注意事项.当然也会给出几种多线程的案例,在实际使用中感受它们的区别.还有一点需要说明的是 ...

  9. java 线程 原子性_深入理解Java多线程与并发框架——Java内存模型与原子性、可见性、有序性...

    欢迎关注专栏<Java架构筑基>--专注于Java技术的研究与分享!Java架构筑基​zhuanlan.zhihu.comJava架构筑基--专注于Java技术的研究与分享! 后续文章将首 ...

最新文章

  1. 虚拟机种mysql的安装_RedHat7.0虚拟机下mysql安装
  2. 2020-11-25(《深入理解计算机系统》多级页表详解)
  3. 逆向查找_CTFer成长之路--一道数独逆向题目解题过程(算法分析、查找线索)...
  4. 2019DTCC大会分享:分布式数据库全局读一致性
  5. Linux中mysql的卸载和重装,在Linux下面卸载与重新安装Postgresql
  6. 利用tabluea分析数据的案例_利用德温特分析Dartsip的案例检索结果
  7. IOS--CALayer的介绍及使用技巧
  8. 【李宏毅机器学习】Basic Concept 基础概念(p4) 学习笔记
  9. 开源框架_跨平台开源框架对比介绍
  10. Jetson Xavier中安装DIGITS-》Caffee中的错误
  11. python第三方库怎么下载安装_简谈下载安装Python第三方库的三种方法
  12. java 前端ui框架_5 个优秀前端 UI 框架
  13. 网页设计与制作项目三“网上花店”
  14. mysql重启报without updating PID file错
  15. 学完了Scratch,我要开始学Python了~~~
  16. unable to close due to unfinalized statements or unfinished backups
  17. Nginx 负载均衡和动静分离
  18. Java中,如何把ascii码转换成字符?
  19. 差分放大电路知识总结
  20. 河南的抗疫英雄,给出一系列抗疫英雄的姓名和来自的省份,现在请你帮忙统计来自河南的抗疫英雄有多

热门文章

  1. MySQL中的调度器
  2. Mybatis plus修改了Language Level后,IDEA运行应用出现了Information:java: javacTask: 源发行版 8 需要目标发行版 1.8
  3. 使用MyBatis Plus 3.2.0版本插件代码生成器生成实体类后,对于数据库中字段类型datetime的字段会转变为LocalDateTime类型
  4. sql server oracle特点,SQL Server 和 Oracle 以及 MySQL 有哪些区别
  5. java的VIRT高的问题理解
  6. 获得输入框的文本document.getElementById('id').value;
  7. matlab求微分方程精确解,matlab求微分方程精确解及近似解.ppt
  8. 定时器精度对性能的影响_Comet CAA-500天线分析仪 | 高精度模拟十字针同时显示SWR和阻抗...
  9. SpringBoot中修改MySQL数据库建表方言
  10. Windows 禁止mysql 自动更新