一、多线程产生安全问题

1、Java内存模型
共享内存模型指的就是Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见。

从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:

线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。

本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

1.主内存:存放多线程操作的共享变量 比如count=0

2.本地内存:存储了当前该线程以读/写共享变量的副本,副本 count1=0,count2=0

多线程同时进行变量操作时比如,对count进行++,先对副本进行++为1,将副本刷新到主内存,由于两个线程是不可见的,共享变量变为1,理论为2,但是还是1 ,

2.不可见

3.可见性

线程A与线程B之间如要通信的话,必须要经历下面2个步骤:

  1. 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。

  2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

下面通过示意图来说明这两个步骤:

二、Volatile

什么是Volatile

可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。

在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。

Volatile 保证了线程间共享变量的及时可见性,但不能保证原子性

class ThreadVolatileDemo extends Thread {public  boolean flag = true;@Overridepublic void run() {undefinedSystem.out.println("开始执行子线程....");while (flag) {undefined}System.out.println("线程停止");}public void setRuning(boolean flag) {this.flag = flag;}}public class ThreadVolatile {public static void main(String[] args) throws InterruptedException {ThreadVolatileDemo threadVolatileDemo = new ThreadVolatileDemo();threadVolatileDemo.start();Thread.sleep(3000);threadVolatileDemo.setRuning(false);System.out.println("flag 已经设置成false");Thread.sleep(1000);System.out.println(threadVolatileDemo.flag);}}

运行结果:

已经将结果设置为fasle为什么?还一直在运行呢。

原因:线程之间是不可见的,读取的是副本,没有及时读取到主内存结果。

解决办法使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值

2、Volatile特性

1.保证此变量对所有的线程的可见性,这里的“可见性”,如本文开头所述,当一个线程修改了这个变量的值,volatile 保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。但普通变量做不到这点,普通变量的值在线程间传递均需要通过主内存(详见:Java内存模型)来完成。

2.禁止指令重排序优化。有volatile修饰的变量,赋值后多执行了一个“load addl $0x0, (%esp)”操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置),只有一个CPU访问内存时,并不需要内存屏障;(什么是指令重排序:是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理)。

volatile 性能:

volatile 的读性能消耗与普通变量几乎相同,但是写操作稍慢,因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。

(1)从而我们可以看出volatile虽然具有可见性但是并不能保证原子性。

(2)性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized。

但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。

java 线程安全的原因_java的多线程:java安全问题产生的原因与JMM的关系相关推荐

  1. java线程开启不了_Java中多线程启动,为什么调用的是start方法,而不是run方法?...

    前言 大年初二,大家新年快乐,我又开始码字了.写这篇文章,源于在家和基友交流的时候,基友问到了,我猛然发现还真是这么回事,多线程启动调用的都是start,那么为什么没人掉用run呢?于是打开我的ide ...

  2. java 线程不安全例子_Java中多线程安全问题实例分析

    案例package com.duyang.thread.basic.basethread; /** * @author :jiaolian * @date :Created in 2020-12-16 ...

  3. java线程中的死锁_Java多线程中的死锁 - Break易站

    Java 多线程 synchronized关键字用于使类或方法线程安全,这意味着只有一个线程可以锁定同步方法并使用它,其他线程必须等到锁定释放并且其中任何一个获得该锁定. 如果我们的程序在多线程环境中 ...

  4. java线程看不进去_Java多线程和并发基础面试问答,看过后你不会后悔

    第一:Java多线程面试问题 1:过程和线程之间有什么不合? 一个过程是一个自力(self contained)的运行情况,它可以被看作一个法度榜样或者一个应用.而线程是在过程中履行的一个义务.Jav ...

  5. java线程池拒绝策略_Java核心知识 多线程并发 线程池原理(二十三)

    线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后 启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕, 再从队列中取出任务来执行.他 ...

  6. java线程休眠sleep函数_Java多线程中sleep()方法详解及面试题

    一. Java线程生命周期(五个阶段) 新建状态就绪状态运行状态阻塞状态死亡状态 如图 二.sleep方法 API中的解释 static voidsleep(long millis) 使当前正在执行的 ...

  7. java线程如何避免死锁_Java面试问题,如何避免Java线程中的死锁?

    如何避免Java中的死锁?是流行的Java面试问题之一,也是多线程的流行话题之一.尽管问题看起来很简单,但是一旦深入,大多数Java开发人员就会陷入困境. 面试问题以"什么是死锁?" ...

  8. java 线程池 源码_java线程池源码分析

    我们在关闭线程池的时候会使用shutdown()和shutdownNow(),那么问题来了: 这两个方法又什么区别呢? 他们背后的原理是什么呢? 线程池中线程超过了coresize后会怎么操作呢? 为 ...

  9. java线程池 的方法_JAVA线程池的实现方法

    我们大家都知道,在处理多线程服务并发时,由于创建线程需要占用很多的系统资源,所以为了避免这些不必要的损耗,通常我们采用线程池来解决这些问题. 线程池的基本原理是,首先创建并保持一定数量的线程,当需要使 ...

最新文章

  1. mysql 切表_mysql--------命令来操作表
  2. 进阶学习(3.9) Bridge Pattern 桥接模式
  3. 《鬼泣V》:旧时代的标杆在新时代的窘境
  4. 前端学习(1734):前端系列javascript之发行
  5. JavaOne大事纪:IBM谈OpenJ9和Open Liberty
  6. 开源 非开源_在开源中吃我们自己的狗粮
  7. Eclipse自定义启动画面和状态栏图标以及各种小图标的含义
  8. 正则表达式及grep
  9. hadoop常见问题汇总
  10. 简易版百度换肤之background属性
  11. 空间计量经济学 matlab,空间计量经济学基于MATLAB的应用分析
  12. 磁盘管理之动态磁盘和静态磁盘的区别
  13. java高速公路收费管理计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
  14. 手机怎么模拟125k卡_NFC手机能模拟门禁卡吗?
  15. 实时数据库和关系数据库的区别、对比
  16. 使用EXCEL计算日期差时间差
  17. 01.ingest pipeline的使用简介
  18. Java零基础学习Java编程语言基础知…
  19. linux云主机安全加固
  20. c++文件读取、容器(vector、map)、迭代(iterator)、排序(sort)综合案例

热门文章

  1. flask 部署_只需10分钟!就能用Flask,Docker和Jenkins部署机器学习模型
  2. c++stl和std_std :: rotate()函数以及C ++ STL中的示例
  3. vb mysql 表格显示,在VB中编辑数据库和电子表格
  4. 某个JAVA类断点无效_解决eclipse中断点调试不起作用的问题
  5. python多行注释以三个英文_Python中多行注释可以包含在三对英文半角单引号('''''')或三对英文半角双引号(\\\...
  6. mac mysql 默认字符集_MacOS中Mysql设置默认字符集
  7. Java类类getDeclaredMethod()方法及示例
  8. 认真聊一下MySQL索引的底层实现!
  9. 面经分享:历时半个月,终于拿到了蚂蚁金服的offer!
  10. 八种常见的 SQL 错误用法