线程的原子性、可见性、有序性及线程安全知识整理

要想保证线程安全,必须同时满足原子性、可见性、有序性。

一、定义

1.1 原子性

一个操作或者多个操作,要么全部执行,并且执行的过程不会被打断, 要么就全部不执行(一个操作是不可被分割的)。

Java中实现线程原子性主要有两种方式:

1、互斥锁:在同一时刻只允许一个线程对共享资源进行访问和操作,而其他线程则需要等待锁的释放才能继续执行。如:synchronized和ReentrantLock等机制来实现锁的获取、释放和等待。

2、原子变量类:Java提供了一些基本类型的原子变量类(如 AtomicInteger、AtomicBoolean 等),这些变量类保证了读取和修改操作的原子性,从而避免了线程安全问题。

我们来看下几个例子:

a = 0 是原子操作 
a++ (a = a + 1) 则不是。因为有两步操作。

我们看一段Java原子性测试代码,使用AtomicInteger类实现对一个共享变量的递增操作。AtomicInteger类提供了compareAndSet方法,可以在多线程并发操作时保证对共享变量的修改都是原子性的

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicTest implements Runnable {
    
    private AtomicInteger count = new AtomicInteger(0);
    
    public void run() {
        for (int i = 0; i < 10000; i++) {
            // 原子性自增
            count.incrementAndGet(); 
        }
    }
    //创建了两个线程,并在每个线程中执行10000次count.incrementAndGet()方法,
    //即对共享变量count进行原子性自增操作。最后在主线程中输出count的值
    public static void main(String[] args) throws InterruptedException {
        AtomicTest test = new AtomicTest();
        
        Thread thread1 = new Thread(test);
        Thread thread2 = new Thread(test);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
        
        System.out.println("count=" + test.count.get());
    }
}

1.2 可见性

是指线程之间的可见性,一个线程修改的状态,对另一个线程是可见的。(也就是一个线程修改的结果,另一个线程能立马知道)。

在多线程并发编程中,由于每个线程都有自己线程栈和本地内存,因此存在一个问题:一个线程修改了共享变量的值,但是由于各种原因(比如缓存、处理器优化等),其他线程可能不会立即知道这个共享变量的最新值,这就导致了访问线程之间的数据不一致。

在java 中 synchronized、 final、 volatile实现可见性。

比如:使用volatile 修饰的变量,就具有可见性, volatile不允许线程内进行缓存和重排序,直接修改内存,所以对其他线程是可见的。

volatile虽然具有可见性,但不具有原子性:

eg:
我们定义一个变量,并进行 +1操作
volatile int i = 0;
i++;

此时i 具有可见性,但不具有原子性,如果多个线程同时对同一个volatile变量进行写操作,由于没有互斥机制,仍然会存在竞态条件问题。

1.3 有序性

程序执行时顺序按照代码但先后顺序执行。
在这里插入图片描述
比如下面这个,语句 1、2的顺序就可以调换, 3、4的则不行。

int a = 10;    //语句1
int r = 2;    //语句2
a = a + 3;    //语句3
r = a*a;     //语句4

二、线程安全

2.1、什么是线程安全

线程安全指内存的安全。这和操作系统有关,
在每个进程的内存空间中都会有一块特殊的公共区域,通常称为堆(内存)。
进程内的所有线程都可以访问到该区域,这就是造成问题的潜在原因。

所以线程安全指的是,在堆内存中的数据由于可以被任何线程访问到,
在没有限制的情况下存在被意外修改的风险。
即堆内存空间在没有保护机制的情况下,对多线程来说是不安全的地方,
因为你放进去的数据,可能被别的线程“破坏”。

2.2、为什么多线程不安全

进程中,有很多数据是多线程之间共享的,这些共享的数据很可能被其他线程修改了,那么线程之间共享了哪些进程资源呢?我们接着往下看,线程间数据的操作过程如下:

线程在执行时,先从主存中读取数据,然后复制一份到高速缓存中,
计算完后,再刷新到主存中。
 ____________      _______________
|cpu  高速缓存|   |  缓存一致性协议|
. -----------     |              |
|cpu  高速缓存|   |       or     |      主存
. -----------     |              |
|cpu  高速缓存|   |   总线锁机制   |
. -----------     |______________|

我们都知道进程是操作系统进行资源分配和调度的基本单位,线程thread是操作系统能够进行运算调度的最小单位,所以在某个进程里面,进程的所有资源对于这个进程里的所有线程来说是共享的,既然是共享的,所以在并发操作里,我们的数据就很有可能不安全,比如我们同时用两个线程对count1分别相加,等到的结果是不确定的。

2.2.1 哪些资源是线程私有的?

我们找到独属于线程的资源,其他的资源都是共享的,我们可以这么理解,线程运行的本质就是函数的执行,函数运行时的信息保存在栈帧中,栈帧中保存了函数的返回值、调用其它函数的参数、该函数使用的局部变量以及该函数使用的寄存器信息。

因此每个线程都有自己独立的、私有的栈区,
以上这些信息有一个统一的名字,就是线程上下文,thread context。

除此之外,剩下的都是线程间共享资源。
借用一张网络图片,如下
在这里插入图片描述

2.3 如何解决线程安全问题?

1、私有化
2、ThreadLocal
3、(互斥)锁
4、cas操作
等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18513.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ApiPost简单使用

目录 环境与变量 设置与使用 随机参数变量 内置Mock字段随机参数 自定义随机参数 全局参数 使用手册 apipost可支持一键压测和自动化接口测试 环境与变量 设置与使用 设置 环境变量可设置环境名称、变量名称、变量初始值、URL&#xff1a; 可以在请求变量或者接口 URL…

攻防世界-web-simple js

题目描述&#xff1a;小宁发现了一个网页&#xff0c;但却一直输不对密码。(Flag格式为 Cyberpeace{xxxxxxxxx} ) 打开链接&#xff1a; 然后我们会发现不管我们输入什么密码&#xff0c;发现是都是这样的报错 1. 先用bp抓包看看&#xff0c;可以抓到这样的一串js脚本 看不懂…

matlab实现BP神经网络(完整DEMO)

本站原创文章&#xff0c;转载请说明来自《老饼讲解-BP神经网络》bp.bbbdata.com 目录 一、BP神经网络Demo代码 1.1 代码整体思路 1.2 BP神经网络Demo代码 二、运行结果 2.1 拟合曲线 2.2训练误差与预测误差 三、相关文章 3.1-BP的入门学习目录&#xff1a;老饼…

JavaScript经典教程(七)-- JavaScript初级

190&#xff1a;JavaScript初级内容 - DOM查询、插入内容、赋予样式等 1、DOM操作 DOM&#xff1a;节点&#xff0c;也就是html中的元素&#xff1b; DOM操作&#xff1a;其实就是节点元素的方法&#xff1b; &#xff08;1&#xff09;innerHTML - 返回元素内容 同时也可以…

关于maven

一、maven是什么 一个java项目构建工具 二、maven的作用 &#xff08;1&#xff09;依赖管理 不同框架整合&#xff0c;互相依赖jar包版本不同&#xff0c;版本不一样&#xff0c;程序跑起来就会报错。用maven管理jar包。 &#xff08;2&#xff09;跨平台构建项目 linux服…

数据结构学习记录——堆的建立(最大堆的建立、思路图解、代码实现、代码解释)

目录 最大堆的建立 方法1 方法2 思路图解 代码实现 代码解释 PercDown BuildHeap 最大堆的建立 建立最大堆&#xff1a;将已经存在的N个元素按最大堆的要求存放在一个一维数组中。 方法1 通过插入操作&#xff0c;将N个元素一个一个地插入到一个初始为空的堆中去。…

简述对象检测与图像分类与关键点检测区别

计算机视觉是人工智能的一个多元化领域&#xff0c;旨在检测和识别图像或视频的内容。大多数开始计算机视觉领域之旅的人的常见问题之一是&#xff1a;目标检测、图像分类和关键点检测之间有什么区别&#xff1f; 让我们先看看 什么是对象检测 对象检测是一种计算机视觉和图像…

excel中英文互译

在excel运行宏时弹出下面的提示&#xff1a; 无法运行“XXXXX”宏。可能是因为该宏在此工作薄中不可用&#xff0c;或者所有的宏都被禁用的错误提示 解决办法&#xff1a; 1、点击“文件”选项卡&#xff1b; 2、在选项卡界面窗口中选择“选项”按钮&#xff1b; 3、在“选项…

JavaScript实现在键盘输入按键,浏览器进行显示的代码

以下为实现在键盘输入按键&#xff0c;浏览器进行显示的代码和运行截图 目录 前言 一、在键盘输入按键&#xff0c;浏览器进行显示 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xf…

智能汽车实验二(视觉传感器标定)

实验二 视觉传感器标定&#xff08;实验报告&#xff09; 【实验目的】 1、了解开源图像处理库OpenCV的结构&#xff0c;掌握OpenCV的基本使用方法。 2、了解开源图像处理库OpenCV的基本模块功能&#xff0c;掌握常用图像处理方法。 3、掌握摄像机标定算法&#xff0c;学会使用…

igraph的layout布局

做图论的社区检测&#xff0c;需要画图显示&#xff0c;用igraph可以进行可视化。 igraph有几个布局&#xff0c;分别如下&#xff1a; layout_with_dh &#xff1a; The Davidson-Harel layout algorithm Place vertices of a graph on the plane, according to the simulat…

113-Linux_安装c/c++开发库及连接mysql数据库

文章目录 一.安装c/c开发库二.连接mysql数据库三.用户的管理与授权 mysql数据库的安装 一.安装c/c开发库 安装开发c/c的库&#xff0c;命令&#xff1a;apt install libmysqlclient-dev 二.连接mysql数据库 #include<stdio.h> #include<mysql/mysql.h>void fun…

Python+Selenium4环境搭建

set集合 怎么把列表种相同的数据和不同的数据取出来 1.把列表转为set集合 2.按照集合的交集 selenium 自动化测试&#xff1a;自动化测试就是通过代码或者是工具模拟人的行为来进行对WEB&#xff08;APP&#xff09;来进行操作。 QTP (HP公司)&#xff1a;以录制回放的模式…

CSS进阶

01-复合选择器 定义&#xff1a;由两个或多个基础选择器&#xff0c;通过不同的方式组合而成。 作用&#xff1a;更准确、更高效的选择目标元素&#xff08;标签&#xff09;。 后代选择器 后代选择器&#xff1a;选中某元素的后代元素。 选择器写法&#xff1a;父选择器 …

学系统集成项目管理工程师(中项)系列19b_成本管理(下)

1. 成本估算 1.1. 编制完成项目活动所需资源的大致成本 1.2. 在设计阶段多做些额外的工作可能减少执行阶段和产品运行时的成本 1.3. 项目估算的准确性随着项目的进展而提高 1.3.1. 【19下选48】 1.4. 针对完成活动所需资源的可能成本进行的量化评估 1.5. 容易被忽视的主要…

华为pbr双出口外线,指定内网单个vlan绑定单个出口外线上网

公司两条外线&#xff0c;vlan 10用nat走上面转发出去上网&#xff0c;vlan 20 走下面那条外线出去nat上网 AR2&#xff1a; interface GigabitEthernet0/0/0 ip address 6.6.6.1 255.255.255.0 interface GigabitEthernet0/0/1 ip address 154.1.2.3 255.255.255.0 interface…

JavaScript通过js的方式来判断一个数奇偶性的代码

以下为通过js的方式来判断一个数奇偶性的程序代码和运行截图 目录 前言 一、通过js的方式来判断一个数奇偶性&#xff08;html部分&#xff09; 1.1 运行流程及思想 1.2 代码段 二、通过js的方式来判断一个数奇偶性&#xff08;js部分&#xff09; 2.1 运行流程及思想 2…

Linux操作系统如何查看CPU型号信息?一条命令搞定

Linux操作系统服务器如何查看CPU处理器信息&#xff1f;使用命令cat /proc/cpuinfo可以查看CPU详细信息&#xff0c;包括CPU核数、逻辑CPU、物理CPU个数、CPU是否启用超线程等&#xff0c;阿里云服务器网分享Linux服务器查看CPU信息命令&#xff1a; 目录 Linux服务器查看CPU…

2023年贵州省职业技能大赛“网络安全” 项目比赛任务书

2023年贵州省职业技能大赛“网络安全” 项目比赛任务书 三、竞赛任务书内容 &#xff08;一&#xff09;拓扑图 &#xff08;二&#xff09;A模块基础设施设置/安全加固&#xff08;200分&#xff09; 一、项目和任务描述&#xff1a; 假定你是某企业的网络安全工程师&…

【Linux】Linux安装Redis(图文解说详细版)

文章目录 前言第一步&#xff0c;下载安装包第二步&#xff0c;上传安装包到/opt下&#xff08;老规矩了&#xff0c;安装包在opt下&#xff09;第三步&#xff0c;解压安装包第四步&#xff0c;编译第五步&#xff0c;安装第六步&#xff0c;配置redis第七步&#xff0c;设置开…