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

JavaEE之线程(4)——线程安全、线程安全的原因,synchronized关键字

前言

在本栏的前面的内容中,我们介绍了线程的创建、Thread 类及常见方法、线程的状态,今天我们来介绍一下关于线程的另一个重点知识——线程安全。

一、线程安全

基本概念:

线程安全的确切定义是复杂的,但我们可以这样认为:如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的。

我们给出一个具体例子,这个自加到10000的例子将会很好的体现线程安全:

static class Counter {public int count = 0;void increase() {count++;}
}public static void main(String[] args) throws InterruptedException {final Counter counter = new Counter();Thread t1 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 50000; i++) {counter.increase();}});t1.start();t2.start();t1.join();t2.join();System.out.println(counter.count);-----------------------------------------------输出结果:59970
}

那么问题来了,理想输出结果为100000,但实际结果为什么不符合呢?

二、线程不安全的原因

首先,让我们理解一下什么是原子性

2.1 什么是原子性

 我们把一段代码想象成一个房间,每个线程就是要进入这个房间的人。如果没有任何机制保证,A进入房间之后,还没有出来;B 是不是也可以进入房间,打断 A 在房间里的隐私。这个就是不具备原子性的。
那我们应该如何解决这个问题呢?

是不是只要给房间加一把锁,A 进去就把门锁上,其他人是不是就进 不来了。这样就保证了这段代码的原子性了

一条 java 语句不一定是原子的,也不一定只是一条指令
比如刚才我们看到的 n++,其实是由三步操作组成的:

  1. 从内存把数据读到 CPU
  2. 进行数据更新
  3. 把数据写回到 CPU
  4. 不保证原子性会给多线程带来什么问题
    如果一个线程正在对一个变量操作,中途其他线程插入进来了,如果这个操作被打断了,结果就可能是
    错误的。这点也和线程的抢占式调度密切相关。如果线程不是 “抢占” 的,就算没有原子性,也问题不大。

2.2 上述代码错误的具体原因

count++ 这个操作,站在CPU的角度上,count++是由CPU通过三个指令完成的。

  1. load 把数据从内存, 读到 cpu 寄存器中;
  2. add把寄存器中的数据进行 +1;
  3. save 把寄存器中的数据,保存到内存中。

 ;如果是多个线程执行上述代码,由于线程之间的调度顺序是“随机”的,就会导致在有些调度顺序下,上述的逻辑就会出现问题。比如,我们简单选取4种的情况举下例子:
在这里插入图片描述

上图中1、2两种情况没有发生逻辑错误,因此不会发生错误,但是第三、四情况就会调度顺序随机,造成代码结果出现错误。

2.3 线程安全的具体原因

  1. 操作系统对于线程的调度是随机的;
  2. 多个线程同时修改同一个变量
  3. 修改操作不是原子的;
  4. 内存可见性;
  5. 指令重排序。

三、Synchronized关键字

上述出现的线程不安全问题,通过加锁,就能解决上述问题,其中最常用的办法,就是使用synchronized 关键字。

synchronized 在使用的时候,要搭配一个 代码块{ } ;
在已经加锁的状态中,另一个线程尝试同样加这个锁,就会产生“锁冲突/锁竞争”,后一个线程就会阻塞等待-直等到前一个线程解锁为止。

让我们再次回到上面的那个例子,通过加锁便可以加锁线程安全的问题:
实例代码1:

/*** @author Zhang* @date 2024/5/515:43* @Description:*/
class Counter{public int count;// 1)直接修饰普通方法;synchronized public void increase(){count++;}//上面的写法是下面的简化版本public void  increase2(){synchronized(this){count++;}}// 2)修饰静态方法;synchronized public static void increase4(){}public static void  increase5(){synchronized(Counter.class){}}
}
public class Test2 { public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread  t1 = new Thread(()->{for (int i = 0; i < 50000; i++) {counter.increase();}});Thread t2 = new Thread(()->{for (int j = 0; j < 50000; j++) {counter.increase();}});t1.start();;t2.start();t1.join();t2.join();System.out.println("count:"+counter.count);}
}
------------------------------------------------------输出:100000

实例代码2:

public class Test1 {    private static int count = 0;public static void main(String[] args) throws InterruptedException {Object lock= new Object();Thread t = new Thread(()->{for (int i = 0; i < 50000; i++) {synchronized (lock){count++;}}});Thread t2 = new Thread(()->{for (int i = 0; i < 50000; i++) {synchronized (lock){count++;}}});//t、t2同时执行t.start();t2.start();t.join();t2.join();//预期结果100000System.out.println("count: "+count);}
}--------------------------------------------------------
输出:100000

总结

好啦!今天我们讲解了线程安全问题,以及为什么会出现线程安全、如何解决线程安全、synchronized关键字。在本栏(https://blog.csdn.net/2301_80653026/category_12660552.html?spm=1001.2014.3001.5482)的下一节我们将继续介绍线程。

相关文章:

JavaEE之线程(4)——线程安全、线程安全的原因,synchronized关键字

前言 在本栏的前面的内容中&#xff0c;我们介绍了线程的创建、Thread 类及常见方法、线程的状态&#xff0c;今天我们来介绍一下关于线程的另一个重点知识——线程安全。 一、线程安全 基本概念&#xff1a; 线程安全的确切定义是复杂的&#xff0c;但我们可以这样认为&…...

Python3 笔记:分支结构

Python 中选择结构&#xff1a;单分支选择结构、双分支选择结构、多分支选择结构。 1、if 语句是单分支选择结构&#xff0c;其语法形式如下&#xff1a; if 条件表达式: 语句块 如果条件表达式的值为真&#xff0c;即条件成立&#xff0c;语句块将被执行&#xff1b;否…...

《TAM》论文笔记(上)

原文链接 [2005.06803] TAM: Temporal Adaptive Module for Video Recognition (arxiv.org) 原文代码 GitHub - liu-zhy/temporal-adaptive-module: TAM: Temporal Adaptive Module for Video Recognition 原文笔记 What&#xff1a; TAM: Temporal Adaptive Module for …...

【Java的抽象类和接口】

1. 抽象类 1.1 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果 一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 以上代码中…...

今天开发了一款软件,我竟然只用敲了一个字母(文末揭晓)

软件课题&#xff1a;Python实现打印100内数学试题软件及开发过程 一、需求管理&#xff1a; 1.实现语言&#xff1a;Python 2.打印纸张&#xff1a;A4 3.铺满整张纸 4.打包成exe 先看效果&#xff1a; 1. 2.电脑打印预览 3.打印到A4纸效果&#xff08;晚上拍的&#x…...

【C++杂货铺】红黑树

目录 &#x1f308;前言&#x1f308; &#x1f4c1; 红黑树的概念 &#x1f4c1; 红黑树的性质 &#x1f4c1; 红黑树节点的定义 &#x1f4c1; 红黑树的插入操作 &#x1f4c1; 红黑树和AVL树的比较 &#x1f4c1; 全代码展示 &#x1f4c1; 总结 &#x1f308;前言…...

css--控制滚动条的显示位置

各种学习后的知识点整理归纳&#xff0c;非原创&#xff01; ① direction属性 滚动条在左侧显示② transform:scaleY() 滚动条在上侧显示 正常的滚动条会在内容超出规定的范围后在区域右侧和下侧显示在有些不正常的需求下会希望滚动条在上侧和左侧显示自己没有想到好的解决方案…...

华为设备display查看命令

display version //查看版本信息 display current-configuration //查看配置详情 display this //查看当前视图有效配置 display ip routing-table //查看路由表 display ip routing-table 192.168.3.1 //查看去往3.1的路由 display ip interface brief //查看接口下ip信息 dis…...

自动攻丝机进出料激光检测 进料出料失败报警循环手动及关闭报警退出无限循环

/**************进料检测********************/ /***缺料无限次循环 手动退出 超时报警*******/ void check_Pon() // { zstatus0; //报警计数器归零 Signauto1; …...

2024年去除视频水印的5种方法

如果你从事电影剪辑或者视频编辑工作&#xff0c;你经常需要从优酷、抖音、TikTok下载各种视频片段……。 通常这些视频带有水印和字幕。一些免费软件如CapCut、canva、Filmora也会给你制作的视频打上水印&#xff0c;这些水印嵌入在视频内部。 2024年去除视频水印的5种方法 …...

怎么用电脑接收手机文件 用备忘录传输更舒服

在这个数字化时代&#xff0c;手机已经成为我们随身携带的“百宝箱”&#xff0c;里面装满了各种重要的文件、资料和信息。然而&#xff0c;有时我们需要在电脑上处理这些文件&#xff0c;比如编辑文档、制作PPT或是查看照片。那么&#xff0c;如何在电脑与手机之间实现文件的顺…...

微信小程序、uniapp密码小眼睛

直接上代码喔喔喔喔喔喔喔喔~~ <input name"username" password"{{passwordHideShow}}" placeholder-style"color:#bdbdbd" type"text"maxlength"20" value"{{passwordNumber}}" bindinput"passwordInput…...

【手势操作-复习前一天的内容-预习今天的内容 Objective-C语言】

一、昨天呢,我们学习的是这个,事件 1.事件这一块儿呢,iOS事件,分为三大类, 1)触摸事件 2)加速计事件 3)远程控制事件 2.这个里边呢,我们主要学习的是这个触摸事件,触摸事件里边,就是Touch,touchesBegan:方法里边,有一个touches参数,它是set类型的, 3.Set,…...

​​​【收录 Hello 算法】第 6 章 哈希表

目录 第 6 章 哈希表 本章内容 第 6 章 哈希表 Abstract 在计算机世界中&#xff0c;哈希表如同一位聪慧的图书管理员。 他知道如何计算索书号&#xff0c;从而可以快速找到目标图书。 本章内容 6.1 哈希表6.2 哈希冲突6.3 哈希算法6.4 小结...

rust类型和变量(二)

基础知识 Rust中的变量基础知识 1.在Rust中&#xff0c;使用Iet关键字来声明变量 2.Rust支持类型推导&#xff0c;但你也可以显式指定变量的类型&#xff1a; Ietx:i325;/显式指定x的类型为i32 3.变量名蛇形命名法(Snake Case),i 而枚举和结构体命名使用帕斯卡命名法(Pasca|Ca…...

linux学习:多媒体开发库SDL+视频、音频、事件子系统+处理yuv视频源

目录 编译和移植 视频子系统 视频子系统产生图像的步骤 api 初始化 SDL 的相关子系统 使用指定的宽、高和色深来创建一个视窗 surface 使用 fmt 指定的格式创建一个像素点​编辑 将 dst 上的矩形 dstrect 填充为单色 color​编辑 将 src 快速叠加到 dst 上​编辑 更新…...

基于门控的循环神经网络:LSTM

之前我们介绍了循环神经网络的原理以及实现。但是循环神经网络有一个问题&#xff0c;也就是长期依赖问题。我们之前的01序列预测案例中可以看到&#xff0c;当序列长度到达10以上之后错误就会增多&#xff0c;说明简单的RNN记忆容量较小&#xff0c;当长度更大时就不怎么适用了…...

Web常见的攻击方式及其防御策略

随着互联网技术的快速发展&#xff0c;Web应用已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;Web应用也面临着各种安全威胁和攻击。了解这些常见的攻击方式&#xff0c;并采取有效的防御策略&#xff0c;对于保护Web应用的安全至关重要。 一、常见的Web攻击方…...

关于SQL

数据库简介&#xff1a; 数据库分类 关系型数据库模型&#xff1a; 优点&#xff1a;易于维护&#xff0c;可以实现复杂的查询 缺点&#xff1a;海量数据 读取写入性能差&#xff0c;高并发下数据库的io是瓶颈 是把复杂的数据结构归结为简单的二元关系&#xff08;即二维表…...

大模型时代下两种few shot高效文本分类方法

介绍近年(2022、2024)大语言模型盛行下的两篇文本分类相关的论文&#xff0c;适用场景为few shot。两种方法分别是setfit和fastfit&#xff0c;都提供了python的包使用方便。 论文1&#xff1a;Efficient Few-Shot Learning Without Prompts 题目&#xff1a;无需提示的高效少…...

Linux0.11 中全局描述符表(GDT)

在Linux内核中&#xff0c;全局描述符表&#xff08;Global Descriptor Table&#xff0c;简称GDT&#xff09;是一个关键的数据结构&#xff0c;主要用于管理处理器的内存段和相关的权限与属性。它属于x86架构中的保护模式特性&#xff0c;允许操作系统对内存访问进行更精细的…...

搜维尔科技:数据手套用于外固定虚拟现实模拟 、外固定增强现实模拟

数据手套用于外固定虚拟现实模拟、外固定增强现实模拟 搜维尔科技&#xff1a;数据手套用于外固定虚拟现实模拟、外固定增强现实模拟...

《三》菜单栏_工具栏_状态栏动作与实现

上期我们创建了辣么多的动作&#xff0c;那么这次我们要是开始实现这些动作&#xff0c;撸起袖子来吧&#xff1a; //菜单动作&#xff08;ACtion&#xff09;QAction *newAct;//新建QAction *openAct;//打开QAction *saveAct;//保存QAction *saveAsAct;//另存为QAction *prin…...

基于NTP服务器获取网络时间的实现

文章目录 1 NTP1.1 简介1.2 包结构1.3 UNIX 时间戳和NTP时间戳 2 代码实现2.1 实现步骤2.2 完整代码 3 结果 在某些场景下&#xff0c;单片机需要通过网络获取准确的时间进行数据同步&#xff0c;例如日志记录、定时任务等。然而&#xff0c;单片机本身无法直接获得准确的标准时…...

Web APIs(获取元素+操作元素+节点操作)

目录 1.API 和 Web API 2.DOM导读 DOM树 3.获取元素 getElementById获取元素 getElementsByTagName获取元素 H5新增方法获取 获取特殊元素 4.事件基础 执行事件 操作元素 修改表单属性 修改样式属性 使用className修改样式属性 获取属性的值 设置属性的值 移除…...

Android adb shell关于CPU核的命令

Android adb shell关于CPU核的命令 先使用命令&#xff1a; adb shell 进入控制台。 然后&#xff0c;直接在$后面输入下面命令&#xff0c;针对CPU的命令。 cat /proc/cpuinfo | grep ^processor | wc -l 查看当前手机的CPU是几核的。 cat sys/devices/system/cpu/online …...

基于springboot+mybatis+vue的项目实战之页面参数传递

如图所示&#xff0c;删除操作可以用按钮实现&#xff0c;也可以用超链接来实现。 1、第一种情况&#xff0c;用按钮实现。 html页面相关&#xff1a; <button type"button" click"deleteId(peot.id)">删除</button> <script>new Vue(…...

CSS-浮动

float (浮动) 作用&#xff1a;盒子的顶点是一样的&#xff0c;具备行内块的特征&#xff0c;能设置宽高 属性&#xff1a;float 属性值&#xff1a;left 浮动在网页左边 right 浮动在网页右边 .a{width: 100px;height: 100px;float:left;background-color: red;}.b…...

MFC:字符串处理

例子 //多字节char* szTest "abc多字节";int nLen strlen(szTest);//9//宽字节wchar_t* szTest2 L"abc多字节";int nlen2 wcslen(szTest2);//6//测试项目配置为Unicodewchar_t* szTesz3 TEXT("abcd");//char* -> CStringCString strTes…...

虚拟仿真云平台在教育应用中的优势和意义

虚拟仿真云实验教学平台作为一种新型的教学方法&#xff0c;近年来在高校教育中得到了十分广泛的应用。它通过模拟真实的实验场景和实验操作&#xff0c;让学生在计算机上进行实验操作和数据处理&#xff0c;为学生提供了更加便捷、可靠、有效的实验学习环境。本文&#xff0c;…...