基于多线程并发的常见问题(详解)

 更新时间:2017年10月09日 10:42:43   投稿:jingxian  
下面小编就为大家带来一篇基于多线程并发的常见问题(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

一 概述

1.volatile

保证共享数据一旦被修改就会立即同步到共享内存(堆或者方法区)中。

2.线程访问堆中数据的过程

线程在栈中建立一个数据的副本,修改完毕后将数据同步到堆中。

3.指令重排

为了提高执行效率,CPU会将没有依赖关系的指令重新排序。如果希望控制重新排序,可以使用volatile修饰一个变量,包含该变量的指令前后的指令各自独立排序,前后指令不能交叉排序。

二 常见问题及应对

1.原子性问题

所谓原子性,指的是一个操作不可中断,即在多线程并发的环境下,一个操作一旦开始,就会在同一个CPU时间片内执行完毕。如果同一个线程的多个操作在不同的CPU时间片上执行,由于中间出现停滞,后面的操作在执行时可能某个共享数据被其他线程修改,而该修改并未同步到当前线程中,导致当前线程操作的数据与实际不符,这种由于执行不连贯导致的数据不一致问题被称作原子性问题。

2.可见性问题

可见性问题的出现与线程访问共享数据的方式有关。线程访问堆(方法区)中的变量时,先在栈中建立一个变量的副本,修改后再同步到堆中。如果一个线程刚建立副本,这时另一线程修改了变量,尚未同步到堆中,这时就会出现两个线程操作同一变量的同一种状态的现象,比如i=9,变量i的初始值为9,每一个线程的操作都是减1。两个线程A与B同时访问变量,B先执行i-1,在将结果i=8同步到堆中前,A线程也执行i-1,这时i=9的状态就被执行两次,出现线程安全问题。

线程安全问题产生的原因:一个线程对共享数据的修改不能立即为其他线程所见。

volatile提供了一种解决方案:

一旦一个线程修改了被volatile修饰的共享数据,这种修改就会立即同步到堆中,这样其他数据从堆中访问共享数据时始终获得的是在多个线程中的最新值。

volatile的缺陷:

volatile只能保证一个线程从堆中获取数据时获取的是当前所有线程中的最新值,假如一个线程已经从堆中复制了数据,在操作完成前,其他线程修改了数据,修改后的数据并不会同步到当前线程中。

3.有序性问题

为了提高执行效率,CPU会对那些没有依赖关系的指令重新排序,重新排序后的执行结果与顺序执行结果相同。

例如,在源代码中:

int i=0;
int y=1;

CPU在执行时可能先执行“int y=1;”,接着执行“int i=0;”,执行结果与顺序执行结果相同。

指令重排在单线程环境下是安全的,在多线程环境下就可能出现问题。比如:

线程A:

s=new String("sssss");//指令1
flag=false;//

指令2线程B:

while(flag){
doSome();
}

s.toUpperCase();//指令3如果线程A顺序执行,即执行指令1,再执行指令2,线程B的执行不会出现问题。指令重排后,假如线程A先执行指令2,这时flag=true,切换到线程2,终止循环,执行指令3,由于s对象尚未创建就会出现空指针异常。

有序性问题产生的原因:

一个线程对其他线程对共享数据的修改操作有顺序要求,比如线程B要求线程A先执行指令1,再执行指令2,由于指令重排,实际并未按照要求的顺序执行,这时就出现了线程安全问题。

解决思路:

1.利用同步机制,使得同一时间只有一个线程可以访问共享数据,效率低。

2.使用volatile,一个指令包含volatile修饰的变量,那么这条指令的执行顺序不变,该指令前后的指令可以各自独立重排,无法交叉重排。

以上这篇基于多线程并发的常见问题(详解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 基于mybatis注解动态sql中foreach工具的方法

    基于mybatis注解动态sql中foreach工具的方法

    这篇文章主要介绍了mybatis注解动态sql中foreach工具方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • java Spring MVC4环境搭建实例详解(步骤)

    java Spring MVC4环境搭建实例详解(步骤)

    spring WEB MVC框架提供了一个MVC(model-view-controller)模型-视图-控制器的结构和组件,利用它可以开发更灵活、松耦合的web应用。MVC模式使得整个服务应用的各部分(控制逻辑、业务逻辑、UI界面展示)分离开来,使它们之间的耦合性更低
    2017-08-08
  • 详解spring cloud hystrix缓存功能的使用

    详解spring cloud hystrix缓存功能的使用

    这篇文章主要介绍了详解spring cloudhystrix缓存功能的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • 浅析Java编程中枚举类型的定义与使用

    浅析Java编程中枚举类型的定义与使用

    这篇文章主要介绍了Java编程中枚举类型的定义与使用,简单讲解了enum关键字与枚举类的用法,需要的朋友可以参考下
    2016-05-05
  • 如何通过Java打印Word文档

    如何通过Java打印Word文档

    这篇文章主要介绍了如何通过Java打印Word文档,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 基于Java的正则表达式

    基于Java的正则表达式

    正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念
    2017-05-05
  • Java图书管理系统,课程设计必用(源码+文档)

    Java图书管理系统,课程设计必用(源码+文档)

    本系统采用Java,MySQL 作为系统数据库,重点开发并实现了系统各个核心功能模块,包括采编模块、典藏模块、基础信息模块、流通模块、期刊模块、查询模块、评论模块、系统统计模块以及帮助功能模块
    2021-06-06
  • java中设计模式之适配器模式

    java中设计模式之适配器模式

    这篇文章主要介绍了java中设计模式之适配器模式的相关资料,适配器模式将一个类的接口转换成客户期望的另一个接口。适配器让原本不兼容的类可以合作得亲密无间,需要的朋友可以参考下
    2017-09-09
  • Java手把手必会的实例汉诺塔讲解练习

    Java手把手必会的实例汉诺塔讲解练习

    汉诺塔,传说神在创造世界的时候做了三根金刚石柱子,并在一个教塔里留下了三根金刚石棒,第一根上面从上到下套着64个按从小到大排列的金盘,神命令庙里的众僧将它们一个个地从这根金刚石棒搬到另一根金刚石棒上,大盘不能放在小盘上。最后64个金盘仍然要按从小到大排列
    2021-09-09
  • java实现创建临时文件然后在程序退出时自动删除文件

    java实现创建临时文件然后在程序退出时自动删除文件

    这篇文章主要介绍了java实现创建临时文件然后在程序退出时自动删除文件,从个人项目中提取出来的,小伙伴们可以直接拿走使用。
    2015-02-02

最新评论