当前位置: 首页 > news >正文

并发编程的三大挑战之原子性及其解决方案

目录

一、原子性问题

1、带来原子性问题的原因

 2、如何解决线程切换带来的原子问题

2.1、使用synchronized关键字来保证

2.2、使用CAS来保证原子性

2.3、使用lock锁来保证


一、原子性问题

1、带来原子性问题的原因

线程切换是带来原子的根本原因,java的并发程序是基于多线程的,自然就会涉及到任务切换。而任务切换的时机是可以发生cpu的时间片结束时,由于目前我们使用的编程语言都是高级语言,一条高级语言往往是需要多条CPU指令完成的,例如count++,至少需要三条CPU指令。

  1. 指令1:首先需要把变量count从主内存中加载cpu的寄存器中
  2. 指令2:在寄存器中执行+1操作
  3. 指令3:将结果写入内存(缓存机制可能导致写入的是cpu的缓存而不是内存)

如下图所示,两个线程如果在执行count++的时候,过程如果发生了线程切换,会导致得不到预期的结果2,可能会出现意向不到结果,两个线程对count执行++操作后,在主内存中值为1. 

原子性的定义:原子性指一个操作是不可分割的,不可中断的,一个线程在执行时,另一个线程不会影响到他

private static int count;public static void increment(){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}count++;}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 100; i++) {increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count);}

 2、如何解决线程切换带来的原子问题

本质就是保存这块有非原子的操作语句,同一个时刻只能被一个线程访问到,并且对修改后的值,保证后续线程可见。通常的做法有:

2.1、使用synchronized关键字来保证

之前的increment()方法修改为如下方式:

	public static synchronized void increment(){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}count++;}

2.2、使用CAS来保证原子性

使用CAS来解决的时候,如下所示:

	private static AtomicInteger atomicInteger = new AtomicInteger();public static void increment(){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}atomicInteger.incrementAndGet();}

2.3、使用lock锁来保证

当我们使用锁来保证原子问题时,其示例代码如下:

private static int count = 0;public static  void increment(){ReentrantLock  reentrantLock = new ReentrantLock();try {reentrantLock.lock();Thread.sleep(10);count++;} catch (InterruptedException e) {e.printStackTrace();}finally {reentrantLock.unlock();}}

http://www.lryc.cn/news/33782.html

相关文章:

  • QML动画(其他的动画)
  • Spark 配置项
  • 掌握Vue3模板语法,助你轻松实现高效Web开发
  • Jmeter+Ant+Jenkins接口自动化测试平台搭建
  • ncnn部署(CMakelists.txt)
  • SQL分库分表
  • 大数据分析案例-基于逻辑回归算法构建微博评论情感分类模型
  • 0105深度优先搜索算法非递归2种实现对比-无向图-数据结构和算法(Java)
  • 传统手工数据采集耗时耗力?Smartbi数据填报实现数据收集分析自动化
  • 《Spring源码深度分析》第5章 Bean的加载
  • 华为OD机试真题Java实现【求最大数字】真题+解题思路+代码(20222023)
  • Java——异常机制
  • 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(下)
  • ESP32设备驱动-土壤湿度传感器驱动
  • 公网远程连接MongoDB数据库【内网穿透】
  • SQL注入——floor报错注入
  • P6入门:在EPS下创建项目(P6Professional)
  • Linux安装及管理应用和账号和权限管理 讲解
  • 【JDK1.8 新特性】Stream API
  • Springboot Maven打包跳过测试的五种方式总结 -Dmaven.test.skip=true
  • 静态链接和动态链接的区别
  • MATLAB学习笔记1
  • Gorm -- 查询记录
  • 「Python 基础」错误、调试与测试
  • 17万字 JUC 看这一篇就够了(一) (精华)
  • C++右值引用/移动语义
  • 小樽C++ 多章⑧ (叁) 指针与字符串、(肆) 函数与指针
  • Mybatis-Plus
  • yolov8行人识别教程(2023年毕业设计+源码)
  • CAD指令框找不到了怎么调出来?CAD指令框调出方法