Java并发编程三个性质:原子性、可见性、有序性

并发编程

并发程序要正确地执行,必须要保证其具备原子性、可见性以及有序性;只要有一个没有被保证,就有可能会导致程序运行不正确

线程不安全在编译、测试甚至上线使用时,并不一定能发现,因为受到当时的CPU调度顺序,线程个数、指令重排的影响,偶然触发

线程安全的定义

比如说一个类,不论通过怎样的调度执行顺序,并且调用处不用对其进行同步操作,其都能表现出正确的行为,则这个类就是线程安全的

并发编程三个概念

原子性: 一个操作或多个操作要么全部执行且执行过程不被中断,要么不执行

可见性: 多个线程修改同一个共享变量时,一个线程修改后,其他线程能马上获得修改后的值

有序性 : 程序执行的顺序按照代码的先后顺序执行

具体实现

 

可以通过 synchronized和Lock实现原子性,因为synchronized和Lock能够保证任一时刻只有一个线程访问该代码块

Java提供了volatile关键字保证可见性

synchronized和lock也可保证可见性,在加锁时其他线程无法访问共享资源

可以通过volatile关键字来保证一定的“有序性”

java提供的解决线程不安全的类:java.util.concurrent.atomic

Atomic类并不使用同步锁,而是采用CAS操作,每次对值进行修改时,先判断其预期值与内存值是否相同,若相同则修改,否则不修改

优点 不加锁,性能较快

缺点 高并发情况下,出错概率越大,长时间CAS不成功,导致CPU消耗过大

注:此种方法是乐观锁,即操作前认为此次操作不会出现竞态,不加锁,只在最后写入主存时进行判断

:ABA问题,当一个值原来是A,被某个线程改成B,又被另个线程改成A,此时CAS操作判断不出已经发生变化,java中使用版本号来解决此问题

内置锁

java中以synchronized关键字来支持原子性

重入锁

当一个线程已获得锁时,再继续试图获得它已经得到的锁时,这个请求是成功的。

重入锁意味着锁的粒度是线程,而不是每个方法调用

重入实现方法:为每个锁关联一个计数器和所有者线程,当计数值为0,即当前没有任何线程获得锁,当线程请求时,JVM记下锁的持有者,计数值置1,当该线程又请求锁时,计数值递增,等其释放,递减到0,锁被释放。

作用 避免死锁

原文地址:https://www.cnblogs.com/shoshana-kong/p/10562249.html

时间: 2024-10-13 00:13:06

Java并发编程三个性质:原子性、可见性、有序性的相关文章

并发编程三要素:原子性,有序性,可见性

并发编程三要素 原子性:一个不可再被分割的颗粒.原子性指的是一个或多个操作要么全部执行成功要么全部执行失败. 有序性: 程序执行的顺序按照代码的先后顺序执行.(处理器可能会对指令进行重排序) 可见性: 一个县城对共享变量的修改,另一个线程能够立刻看到. 一.原子性 线程切换会带来原子性的问题 int i = 1; // 原子操作 i++; // 非原子操作,从主内存读取 i 到线程工作内存,进行 +1,再把 i 写到主内存. 虽然读取和写入都是原子操作,但合起来就不属于原子操作,我们又叫这种为"

Java 并发编程(三):如何保证共享变量的可见性?

上一篇,我们谈了谈如何通过同步来保证共享变量的原子性(一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行),本篇我们来谈一谈如何保证共享变量的可见性(多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值). 我们使用同步的目的不仅是,不希望某个线程在使用对象状态时,另外一个线程在修改状态,这样容易造成混乱:我们还希望某个线程修改了对象状态后,其他线程能够看到修改后的状态——这就涉及到了一个新的名词:内存(可省略)可见性. 要了解可见性

Java并发编程(六)原子性与易变性

原子性 原子是最小单元.不可再分的意思.原子性是指某个操作在获取CPU时间时,要么就给它足够时间,让这个操作执行完,要么就不执行这个操作,执行时不能出现上下文切换(把CPU时间从一个线程分配到另一个线程). Java中对变量的读取和赋值都是原子操作,但long.double类型除外,只有使用volatile修饰之后long.double类型的读取和赋值操作才具有原子性.除此之外Java还提供了几个常用的原子类,原子类的方法是具有原子性的方法,也就是说原子类在执行某个方法的过程中不会出现上下文切换

JAVA并发编程学习笔记------对象的可见性及发布逸出

一.非原子的64位操作: 当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性.最低安全性适用于绝大多数变量,但存在一个例外:非volatile类型的64位数值变量(double,long),Java内存模型要求,变量的读取和写入操作都必须是原子操作,但对于非volatile型的long,double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作,当读取一个非volatile类型的long

Java并发编程(三) 并发类库中的常用类

1. 同步容器类 遗留下来的同步容器类包括Vector和Hashtable,此外java.util.Collections类中还提供了以下工厂方法创建线程安全的容器对象: Collections.synchronizedList 返回支持同步操作(线程安全)的List对象: Collections.synchronizedSet 返回支持同步操作(线程全的)的Set对象: Collections.synchronizedMap 返回支持同步操作(线程安全)的Map对象: 需要注意的是,同步容器类

[Java并发编程实战] 共享对象之可见性

「 盛年不重来,一日难再晨,及时当勉励,岁月不待人.」 陶渊明 我们已经知道同步代码块和同步方法可以保证以原子的方式执行,其实,同步还有另外一个重要概念:内存可见性.换句话说,我们不仅希望防止某个线程正在使用对象状态而另一个线程同时在修改状态,而且希望确保当一个线程修改了对象的状态后,其他线程能够看到修改后的状态. 可见性 一个线程对共享变量值的修改,能够及时的被其他线程看到.可见性微妙的,这是因为可能发生错误的事情总是与直觉大相径庭.来看下面这个例子和他的执行结果: 1public class

《java并发编程的艺术》读书笔记-第三章Java内存模型(二)

一概述 本文属于<java并发编程的艺术>读书笔记系列,第三章java内存模型第二部分. 二final的内存语义 final在Java中是一个保留的关键字,可以声明成员变量.方法.类以及本地变量.可以参照之前整理的关键字final.这里作者主要介绍final域的内存语义. 对于final域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序. 初次读一个包含final域的对象的引用,与随后初次读这

&lt;java并发编程的艺术&gt;读书笔记-第三章java内存模型(一)

一概述 本文属于<java并发编程的艺术>读书笔记系列,继续第三章java内存模型. 二重排序 2.1数据依赖性 如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性.数据依赖分下列三种类型: 名称 代码示例 说明 写后读 a = 1;b = a; 写一个变量之后,再读这个位置. 写后写 a = 1;a = 2; 写一个变量之后,再写这个变量. 读后写 a = b;b = 1; 读一个变量之后,再写这个变量. 上面三种情况,只要重排序两个操作的执行顺序,

Java并发编程(三)volatile域

相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Android多线程(一)线程池 Android多线程(二)AsyncTask源代码分析 前言 有时仅仅为了读写一个或者两个实例域就使用同步的话,显得开销过大,volatile关键字为实例域的同步訪问提供了免锁的机制.假设声明一个域为volatile,那么编译器和虚拟机就知道该域是可能被还有一个线程并发更新的. 再讲到volatile关键字之前我们须要了解一下内存模型的相关概念以及并发编程中的三个特性:原子性,可见