【并发编程】什么是线程安全性?

线程安全性

线程安全性定义:
当多个线程访问某个类时,无论运行时环境采用何种调度方式或者这些进程将如何交替执行,而且在主调代码中不须要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。html

三个基本概念

在并发编程中,咱们一般会遇到如下三个问题:原子性问题,可见性问题,有序性问题。咱们先看具体看一下这三个概念:java

原子性

原子性:是指一个操做或多个操做要么所有执行,且执行的过程不会被任何因素打断,要么就都不执行。编程

原子性提供了互斥访问,同一时刻只能有一个线程来对它进行操做。缓存

可见性

可见性:当一个线程修改了线程共享变量的值,其它线程可以当即得知这个修改。安全

一个线程对主内存的修改能够及时的被其余线程观察到。Java内存模型是经过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存做为传递媒介的方法来实现可见性的,不管是普通变量仍是volatile变量都是如此。多线程

有序性

有序性:即程序执行的顺序按照代码的前后顺序执行。并发

Java内存模型中的程序自然有序性能够总结为一句话:若是在本线程内观察,全部操做都是有序的;若是在一个线程中观察另外一个线程,全部操做都是无序的。前半句是指“线程内表现为串行语义”,后半句是指“指令重排序”现象和“工做内存主主内存同步延迟”现象。app

有序性的语意有几层,高并发

  1. 最多见的就是保证多线程运行的串行顺序
  2. 防止重排序引发的问题
  3. 程序运行的前后顺序。比方JMM定义的一些Happens-before规则

指令重排序不会影响单个线程的执行,可是会影响到线程并发执行的正确性。性能

总结

Java内存模型是围绕着在并发过程当中如何处理原子性、可见性和有序性这3个特征来创建的。
也就是说,要想并发程序正确地执行,必需要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会致使程序运行不正确。

在Java虚拟机规范中试图定义一种Java内存模型(Java Memory Model,JMM)来屏蔽各个硬件平台和操做系统的内存访问差别,以实现让Java程序在各类平台下都能达到一致的内存访问效果。那么Java内存模型规定了哪些东西呢,它定义了程序中变量的访问规则,往大一点说是定义了程序执行的次序。注意,为了得到较好的执行性能,Java内存模型并无限制执行引擎使用处理器的寄存器或者高速缓存来提高指令执行速度,也没有限制编译器对指令进行重排序。也就是说,在java内存模型中,也会存在缓存一致性问题和指令重排序的问题。

Java内存模型规定全部的变量都是存在主存当中(相似于前面说的物理内存),每一个线程都有本身的工做内存(相似于前面的高速缓存)。线程对变量的全部操做都必须在工做内存中进行,而不能直接对主存进行操做。而且每一个线程不能访问其余线程的工做内存。(详细见:【JVM】Java内存模型

那么Java语言 自己对 原子性、可见性以及有序性提供了哪些保证呢?

一、原子性

在Java中,对基本数据类型的变量的读取和赋值操做是原子性操做,即这些操做是不可被中断的,要么执行,要么不执行。也就是说,只有简单的读取、赋值(并且必须是将数字赋值给某个变量,变量之间的相互赋值不是原子操做)才是原子操做。
Java内存模型只保证了基本读取和赋值是原子性操做,若是要实现更大范围操做的原子性,能够经过synchronized和Lock来实现。因为synchronized和Lock可以保证任一时刻只有一个线程执行该代码块,那么天然就不存在原子性问题了,从而保证了原子性。

二、可见性

对于可见性,Java提供了volatile关键字来保证可见性。

当一个共享变量被volatile修饰时,它会保证修改的值会当即被更新到主存,当有其余线程须要读取时,它会去内存中读取新值。

而普通的共享变量不能保证可见性,由于普通共享变量被修改以后,何时被写入主存是不肯定的,当其余线程去读取时,此时内存中可能仍是原来的旧值,所以没法保证可见性。

另外,经过synchronized和Lock也可以保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁而后执行同步代码,而且在释放锁以前会将对变量的修改刷新到主存当中。所以能够保证可见性。

三、有序性

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

在Java里面,能够经过volatile关键字来保证必定的“有序性”。另外能够经过synchronized和Lock来保证有序性,很显然,synchronized和Lock保证每一个时刻是有一个线程执行同步代码,至关因而让线程顺序执行同步代码,天然就保证了有序性。

另外,Java内存模型具有一些先天的“有序性”,即不须要经过任何手段就可以获得保证的有序性,这个一般也称为Happens-before规则。若是两个操做的执行次序没法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机能够随意地对它们进行重排序。

参考资料:

Java的原子性&&可见性&&有序性
Java并发编程:volatile关键字解析
慕课网高并发实战(四)- 线程安全性

相关文章
相关标签/搜索