2.并发中-线程安全问题及三大特性

news2024/11/19 0:41:54

目录

  • 概述
  • 线程
    • 线程安全问题
    • 线程安全的根本原因
    • 验证
      • 代码
      • 执行结果
    • 解决线程安全
      • 代码
      • 结果
    • 线程并发三大特性
      • 指令重排
      • as-if-serial
      • 可见性
        • cpu和缓存一致性
        • java内存模型(java memory model)
        • 解决可见性问题及happens-before
  • 结束

概述

线程

线程安全问题

多个线程同时执行,可能会运行同一行代码,如果程序每次运行结果与单线程执行结果一致,且变量的预期值也一样,就是线程案例的,反之则是线程不安全。

线程安全的根本原因

引发线程安全问题的根本原因:多个线程共享变量

如果多个线程对共享变量只有读操作,无写操作,那么此操作是线程安全的。
如果多个线程同时执行共享变量的写和读操作,则操作不是线程安全的。

验证

下面以多窗口卖票为例

代码

package com.fun.demo;

public class DemoTicket {
    public static void main(String[] args) {
        TicketTask task = new TicketTask();
        new Thread(task, "窗口1").start();
        new Thread(task, "窗口2").start();
        new Thread(task, "窗口3").start();
    }

    static class TicketTask implements Runnable {

        private int tickets = 100;

        @Override
        public void run() {
            while (true) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "-正在卖票:" + tickets--);
                }
            }
        }
    }
}

执行结果

窗口显示
在这里插入图片描述
在这里插入图片描述

解决线程安全

为了解决线程安全问题,java给出了各种办法

  • 同步机制 synchronized
  • volatile 关键字:内存屏障
  • 原子类:cas
  • 锁:AQS
  • 并发容器

代码

package com.fun.demo;

public class DemoTicket {
    public static void main(String[] args) {
        TicketTask task = new TicketTask();
        new Thread(task, "窗口1").start();
        new Thread(task, "窗口2").start();
        new Thread(task, "窗口3").start();
    }

    static class TicketTask implements Runnable {
        private final Object lock = new Object();

        private int tickets = 100;

        @Override
        public void run() {
            while (true) {
                synchronized (lock) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(20);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "-正在卖票:" + tickets--);
                    }
                }
            }
        }
    }
}

结果

执行结果如下:
在这里插入图片描述

线程并发三大特性

很重要的三大特性:

  • 原子性:一个系列指令代码,要么全执行,要么都不执行,执行过程不能被打断
  • 有序性:程序代码按照先后顺序执行
    • 产生无序问题是因为指令重排
  • 可见性:当多个线程访问同一个变量时,一个线程修改了共享变量的值,其它线程能够立即看到
    • 出现可见问题是因为java内存模型(JMM)

指令重排

编译器和处理器会对执行指令进行重排序优化,目的是提高程序运行效率。
现象是,编写的java代码语句的先后顺序,不一定是按照写的顺序执行。

int count = 0;
boolean flag = false;
count =1;// 语句1
flag = true; //语句2

上述代码在执行过程中:语句1不一定在语句2之前先执行,由于指令重排,语句2可能先于指令1执行。

为什么要指令重排?
同步变异步,系统指令层面的优化。

  • 无论如何重排,不会影响最终执行结果,因为大部分指令并没有严格的前后执行顺序。
  • 在单线程情况下,程序执行遵循as-if-serial语义。

as-if-serial

as-if-serial 指不管编译器和处理器怎么重排指令,单线程执行结果不受影响。
看下面例子:

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

上面代码执行的顺序:语句2 —> 语句1—>语句3—> 语句4
不可能是:语句2 —> 语句1—>语句4—> 语句3

总结: 处理器在指令重排时,会考虑指令之间的数据依赖性。

重排不会影响单线程程序正确执行,但是会影响多线程。

看下面例子:

 // 线程1
 boolean init = false;// 语句1
 String context = loadContext(init);// 语句2
 init = true; // 语句3

 // 线程2:
 while (!init) {
     try {
         Thread.sleep(10000);
     } catch (InterruptedException e) {
         e.printStackTrace();
     }
 }
 executeDemo(context);

// 下面是类中方法
private static void executeDemo(String context) {
}

private static String loadContext(boolean init) {
    return "init:" + init;
}

当语句3与语句2执行顺序变化时,在多线程中会发生问题。

可见性

cpu和缓存一致性

在多核cpu中每个核都有自己的缓存,同一个数据的缓存与内存可能不一致。

cpu缓存的诞生是因为cpu执行速度和内存读取速度差距越来越大,导致cpu每次操作内存都要耗费很多等待时间。为了解决这个问题,在cpu和物理内存上新增调整缓存。
程序在运行过程中会将运算所需要数据 从主内存复制到cpu高速缓存,当cpu计算直接操作高速缓存数据时,运算结束将结果刷回主内存。

java内存模型(java memory model)
  • java 为了保证满足原子性,可见性及有序性,诞生了jsr133规范,java内存模型,简称 JMM
  • JMM规范解决了cpu多级缓存、处理器优化、指令重排等导致的内存访问问题

以下是JMM内存模型抽象结构示意图:
在这里插入图片描述

  • JMM定义共享变量何时写入,何时对另一个线程可见
  • 线程之间的共享变量存储在主内存
  • 每个线程都有一个私有的本地内存,本地内存存储共享变量的副本
  • 本地内存是抽象的、不真实存在,涵盖:缓存 、写缓冲区、寄存器等

JMM线程操作内存基本规则:

  • 线程操作共享变量必须在本地内存中,不能直接操作主内存的。
  • 线程间无法直接访问对方的共享变量,需要经过主内存传递。

JMM通过控制线程与本地内存之间的交互,来保证内存可见性。

解决可见性问题及happens-before

使用JMM:synchronized、volatile,遵循了 happens-before 规则

在JMM中使用happens-before规则约束编译器优化行为,java允许编译器优化,但不能无条件优化。

如果一个操作的执行结果需要对另一个操作可见,那么这两个操作必须存在 happens-before 的关系!

  • 程序次序规则:在一个线程内,按照控制流顺序,如果操作A先行发生于操作B,那么操作A所产生的影响对于操作B是可见的。
  • 管程锁定规则:对于同一个锁,如果一个unlock操作先行发生于一个lock操作,那么该unlock操作所产生的影响对于该lock操作是可见的。
  • volatile变量规则:对于同一个volatile变量,如果对于这个变量的写操作先行发生于这个变量的读操作,那么对于这个变量的写操作所产的影响对于这个变量的读操作是可见的。

一言以蔽之:就是当前操作,主内存的变量对需要的线程可见。

结束

并发中-线程安全问题及三大特性,至此结束,如有疑问,欢迎评论区留言。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中石油勘探院张弢:从业务到架构全面探讨中国石油的数字化转型之路

引言:OSDU论坛的诞生与壮大,对油气行业的数字化有极大的推动力,国内油气行业正在紧锣密鼓地开展数字化转型、智能化发展。当前油气上游业务数字化转型正在轰轰烈烈的开展,一些明星油田的数字化率无限接近100%,基于业务…

BGP笔记实验

IGP(Interior Gateway Protocol)——内部网关协议 OSPF RIP IS-IS IGRP EIGRP EGP(External Gateway Protocol)——外部网关协议 EGP BGP——边界网关协议 AS——自治系统 由单一组织or机构独立维护的网络设备&网络资源的集合 网络范围太大 自治 AS号 为了区分不同…

基于V100下Llama2-Atom大模型微调

文章目录 大规模的中文数据预训练模型部署模型微调Step1: 环境准备Step2: 数据准备Step3: 微调脚本Step4: 加载微调模型 一些BUG 大规模的中文数据预训练 原子大模型Atom在Llama2的基础上,采用大规模的中文数据进行持续预训练,包含百科、书籍、博客、新…

算法(圆的定义和相关术语)

无向图的度 图中每一个顶点的度定义为以该项点为一个端点的边的数目 #include <cstdio>const int MAXN 100;int degree[MAXN] { 0 };int main() {int n, m, u, v;scanf("%d%d", &n, &m);//在输出边度的时候就已经表示度的数目了&#xff0c;所以用一…

什么是高防CDN?有什么优势?

德迅高防CDN技术概述 随着互联网的快速发展&#xff0c;网络安全问题越来越受到人们的关注。高防CDN(Content Delivery Network)作为一种有效的网络安全防御手段&#xff0c;在企业和个人网站中得到了广泛应用。本文将详细介绍高防CDN的技术原理、防御原理、优点和应用场景&am…

探伤仪的曲线

超声波检验DAC曲线、AVG曲线的区别、使用及制作方法 一、 概念 1.1 DAC曲线 DAC距离波幅曲线是描述某一确定反射体回波高度随距离变化的关系曲线。因此&#xff0c;AVG曲线和DAC曲线都有纵波、横波制作的曲线&#xff0c;并不是简单地由纵波、横波来划分何为AVG曲线&#xf…

怎么实现在微信公众号秒杀商品的功能呢

实现微信公众号秒杀商品的功能&#xff0c;需要结合微信公众平台和后端开发技术。下面将介绍整个实现过程&#xff0c;包括前期准备、开发流程和后期运营等方面。 一、前期准备 确定秒杀商品&#xff1a;选择适合秒杀的商品&#xff0c;要求数量充足、质量良好&#xff0c;同时…

Python下使用requests库遇到的问题及解决方案

每一盏灯都有一个故事……当凌晨2点我的房间灯还亮着时&#xff0c;那就是我与BUG的一场生死博弈。一个人静静地坐在电脑前不断地写代码&#xff0c;感觉快要麻木了&#xff0c;好比闭关修炼一样枯燥无味。最终当我打通任督二脉后&#xff0c;bug修复迎来的一片曙光。 一、问题…

广东网络广播电视台《明星小主播》栏目开拍 小主持神采奕奕

近日&#xff0c;由广东网络广播电视台的《明星小主播》栏目&#xff0c;在广东广播电视台&#xff08;人民北路&#xff09;广州越秀区人民北路686号主楼五楼火热开拍&#xff0c;幕后花絮曝光。《明星小主播》栏目是一档专业少儿主持类节目&#xff0c;节目旨在培养小朋友的主…

模方4.1.0新版本正式上线啦!

新增单体化自动建模&#xff0c;直角搭桥、复制三角形两种方式补洞等功能&#xff0c;还有更多功能优化&#xff0c;让你的三维模型更好看&#xff01; 欢迎前往官网下载试用→武汉大势智慧-实景三维-云端建模-新型基础设施

适合学校或高校老师、学生学习用的网盘推荐

现代教育中&#xff0c;数字化的教学资源和家长的参与度越来越重要。然而文件传输的问题一直是学校和家长面临的一个挑战&#xff0c;网络限制、U盘病毒和文件管理不便等问题&#xff0c;都对教学质量和家校沟通造成了影响。Zoho WorkDrive企业网盘为学校还有教辅机构提供了一个…

MAX/MSP SDK学习03:Atoms and Messages的使用

今天终于把Message消息选择器看得有点头绪了&#xff0c;主要是这个官方英文文档理解起来有点抽象。 编写IsMatchABC自定义Object&#xff0c;要求&#xff1a; ①若左入口&#xff08;入口0&#xff09;收到 "int" 型消息&#xff0c;则从出口发送数值 "888&q…

做外贸要学会分析客户情况

最近在某产品的专业群里询问一款产品&#xff0c;看谁可以做&#xff0c;然后很快就有一个自称是工厂的人加上了我。因为自己本身并不懂这个产品&#xff0c;很多他们发的问题自己都答不上来。我就如实告诉他自己是个新手&#xff0c;可以把你们现在能做的&#xff0c;或者已经…

数据结构之栈的讲解

&#x1f495;" 春宵一刻值千金&#xff0c;花有清香月有阴。 "&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;leetcode刷题之哈希表的应用(1) 1.栈的概念 栈是一种只允许在一端&#xff08;栈顶&#xff09;进行数据操作的数据结构&#xff0c;具…

一篇文章让你彻底了解Java算法「十大经典排序算法」

✍️作者简介&#xff1a;码农小北&#xff08;专注于Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a; 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&#x1f449;关注✨、点赞&…

Delayed 延时任务

延时任务与定时任务的区别 延时任务&#xff0c;可以理解为定时任务的一种&#xff0c;但是他们是有区别的。 延时任务&#xff1a;将程序代码延时执行&#xff0c;执行完毕&#xff0c;即为结束。 定时任务&#xff1a;周期性执行任务。代码执行完毕后&#xff0c;并不意味着…

2023年中国AI基础设施行业发展趋势分析:AI基础设施将保持高速增长[图]

从产品形态来看&#xff0c;AI基础设施可划分为AI基础硬件和基础软件两大类。而在AI生态系统中&#xff0c;通用型和定制型AI基础设施的相互依赖性促进了广泛的AI技术应用&#xff0c;也为各行业的持续发展提供了关键支持。 AI基础设施分类 资料来源&#xff1a;共研产业咨询&…

windows11系统如何设置锁屏壁纸

1. 在开始页面里面找到设置 2. 在设置里面找到个性化 3. 按照红色圈出部分操作 个性化锁屏界面 选择 图片 浏览照片 选择一张你觉得好看的图片作为锁屏壁纸 注&#xff1a;如果需要在锁屏后的登录页面显示壁纸 请勾选第三个红圈部分

Java基本数据类型与引用类型的区别

基本数据类型存放在栈中&#xff0c;引用数据类型其具体内容存放在堆中栈中存放的是其具体内容所在内存的地址。通过变量地址可以找到变量的具体内容&#xff0c;就像通过房间号可以找到房间一样。 public class Main{public static void main(String[] args){//基本数据类型in…

Active Directory 和域名系统(DNS)的相互关系

什么是域名系统&#xff08;DNS&#xff09; 域名系统&#xff08;DNS&#xff09;&#xff0c;从一般意义上讲是一种将主机名或域名解析为相应IP地址的手段。 在 AD 的中&#xff0c;DNS 服务维护 DNS 域和子域的工作命名空间&#xff0c;这些域和子域主要有助于查找过程&am…