多线程问题(二)(安全问题)

news2024/12/25 12:35:37

目录

一、多线程不安全引例

二、线程不安全的原因 

1、线程是抢占式执行

2、多线程共享同一变量

3、对变量的操作不是原子性 

4、内存可见性 

5、指令重排序 

三、线程不安全问题的解决方案 

1、使用synchronized关键字进行加锁

a、 synchronized修饰普通方法

b、synchronized修饰代码块 

c、synchronized修饰静态方法 

2、使用volatile关键字保证内存可见性 

四、死锁问题 

1、死锁

2、死锁场景

a、一个线程一把锁 

b、两个线程两把锁 

c、m个线程n把锁 

3、死锁产生的四个必要条件 

a、互斥使用 

b、 不可抢占

c、请求和保持 

d、环路等待 

4、wait方法

5、notify()方法 

6、noifyAll()方法


一、多线程不安全引例

使用两个线程同时对count变量进行相加,观察结果。

public class Count {
    public int count;
    void test(){
        count++;
    }
    public static void main(String[] args) throws InterruptedException {
        Count counter = new Count();
        Thread t1=new Thread(()->{
            for(int i=0;i<3000;i++){
                counter.test();
            }
        });
        Thread t2=new Thread(()->{
            for(int i=0;i<3000;i++){
                counter.test();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(counter.count);
    }
}

运行结果:

 

 

此时代码的运行结果并不是6000,并且每次运行得到的结果不一致,运行结果在3000~6000之间,此时多线程并发编程就是不安全的。
线程不安全就是多线程并发执行代码没有得到预期的结果。

二、线程不安全的原因 

1、线程是抢占式执行

线程的抢占式执行就是在一个线程的执行过程中,另一个更优先的进程会抢占当前线程执行的任务,当前线程就会被迫中断,这是引发线程不安全的根本原因,但是线程的调度是随机的,这是由系统决定的,我们无法改变。

2、多线程共享同一变量

多线程共享同一变量如果只是读操作就不会引发线程安全问题,但是如果多线程都修改同一变量就会引发安全问题,就是引例当中的情况,因为修改操作不是原子性,需要多步完成就有可能发生线程抢占导致中断。

3、对变量的操作不是原子性 

操作原子性也就是操作能一步完成,但是修改变量的操作就可以分为:将变量从内存加载到寄存器(load) 、修改变量(update)、把寄存器的值加载回内存(save),那么如果有两个线程对变量进行修改操作由于线程的抢占式执行就会出现以下情况:

安全情况:未发生抢占,两个线程都能按序执行完。

 不安全情况:发生了抢占,应该有多种,仅画出两种说明

出现上述情况导致的结果就是更新丢失,例如是自增操作: 假设内存中的变量的初始值为0,t1就先把0加载到寄存器,但是t2进行抢占,也从内存中把0加载到寄存器然后自增为1,然后将1加载回内存,然后t1再自增为1,再将1加载回内存,按道理两次自增应该为2,但是由于线程的抢占以及自增操作是非原子的就会出现上述情况。

4、内存可见性 

变量通常存放在内存中,线程对变量操作需要首先从内存中拿出到寄存器,但是一个线程频繁进行读操作,就可能会直接从寄存器上读,不再进入内存这就引发线程不安全,因为线程得不到内存中变量的最新值。

5、指令重排序 

指令重排序是编译器的优化操作来提高代码运行的效率,但是对于多线程在进行指令重排序时就可能会出现错误引发线程安全问题。

三、线程不安全问题的解决方案 

1、使用synchronized关键字进行加锁

使用synchronized关键字加锁后可以处理内存可见性和保证原子性,使多线程之间互斥。synchronized可以修饰普通方法、代码块、静态方法。

a、 synchronized修饰普通方法

此时synchronized的加锁对象就是this。

例如将引例编程线程安全,就在test方法前加上synchronize即可。 

synchronized void test(){
        count++;
    }

 运行结果:

b、synchronized修饰代码块 

这里需要显示指定锁对象,在Java中任何对象都可以成为锁对象,对引例的test方法进行修改: 

void test(){
         synchronized(this){
             count++;
         }
    }

c、synchronized修饰静态方法 

 这里相当于是给当前类的类对象加锁。

public synchronized static void method() {
}

2、使用volatile关键字保证内存可见性 

使用volatile只能修饰变量,保证内存的可见性,但是volatile无法保证原子性。

四、死锁问题 

1、死锁

多个线程相互竞争资源而引起的一种僵局,若无外力作用,僵局就会一直保持。

2、死锁场景

a、一个线程一把锁 

一个线程连续加锁两次,如果是不可重入锁,就会发生死锁 

b、两个线程两把锁 

两个线程对各自已有的对象进行上锁,但是执行过程中又需要对方的对象,两个线程此时都不释放锁,就都不能继续执行就会产生死锁。 

c、m个线程n把锁 

例如哲学家吃饭问题。 

3、死锁产生的四个必要条件 

a、互斥使用 

一个锁被一个进程使用之后,其他的线程无法使用。 

b、 不可抢占

一个锁被一个进程使用了之后,其余的线程不能抢走该锁。 

c、请求和保持 

一个锁占用了多把锁之后,除非显示地释放锁,否则这些锁始终都被该线程持有。 

d、环路等待 

等待关系形成了一个环,A等B,B又等A。 

4、wait方法

wait()方法:线程等待方法

线程一旦调用了wait方法后就会进入阻塞状态

调用wait方法后,wait方法内部首先会释放锁,然后进入阻塞状态等待唤醒,收到唤醒通知后重新加锁继续向下执行。

5、notify()方法 

notify()方法:唤醒等待的线程。 

6、noifyAll()方法

notifyAll()方法:唤醒所有等待的线程。

当多个线程都是wait状态时,使用notify()只能随机唤醒一个线程,而notifyAll能唤醒所有的wait线程。 

  • 注意:
  • notify()/wait()是针对同一个对象操作。
  •  notify()/wait()都要搭配synchronized使用。

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

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

相关文章

Maleimide-PEG-Biotin,Biotin-PEG-MAL,生物素PEG马来酰亚胺用于生物分子检测

化学试剂生物素聚乙二醇马来酰亚胺&#xff0c;其英文名为Maleimide-PEG-Biotin&#xff0c;Biotin-PEG-MAL&#xff0c;它所属分类为Biotin PEG Multi-arm PEGs。 该试剂质量控制为95%&#xff0c;试剂的储存条件为&#xff1a; -20℃长期保存&#xff0c;避光&#xff0c;干…

数据结构---图

&#xff08;一&#xff09; 相关知识点 图&#xff08;graph&#xff09;&#xff1a;图是由顶点的有穷非空集合和顶点之间边的集合组成&#xff0c;通常表示为&#xff1a;G(V,E)&#xff0c;其中&#xff0c;G表示一个图&#xff0c;V是图G中的顶点的集合&#xff0c;E是图G…

SpringBoot系列之自动装配原理详解

文章目录前言一、SpringBoot自动配置-Condition-11、观察spring自动创建bean过程2、创建自定义bean对象3、根据条件创建自定义bean二、 SpringBoot自动配置-Condition-2三、SpringBoot自动配置-切换内置web服务器1、查看继承关系图2、shiftdelete 排除Tomcat四、SpringBoot自动…

Win10启动Pycharm报错

Win10启动Pycharm报错报错信息解决方法报错信息 Internal error. Please report to http://jb.gg/ide/critical-startup-errors java.net.BindException: Address already in use: bind at java.base/sun.nio.ch.Net.bind0(Native Method) at java.base/sun.nio.ch.Net.bind(U…

如何在3个月内写出博士论文

在阅读本文之前&#xff0c;请注意&#xff1a;我花了三年半的时间进行全职研究&#xff0c;为我的博士论文收集数据&#xff1b;这三个月只涉及写作&#xff0c;我在最后很快就完成了。我并不是说每个人都能写得那么快&#xff0c;如果你没有做过研究&#xff0c;那是不可能的…

全国各省368个地级市河流密度数据(工具变量)

数据来源&#xff1a;国家基础地理信息中心 时间跨度&#xff1a;-- 区域范围&#xff1a;全国各省市 指标说明&#xff1a; 根据河流矢量和中国城市行政边界矢量地理信息&#xff0c;计算每个城市河流的总长度&#xff1b;根据各城市的行政区划面积&#xff0c;计算中国各城…

第三章:关系数据库标准语言SQL

一、sql概述和数据定义 1、【单选题】 create user A identified by B default tablespace C temporary tablespace D&#xff1b; 上述oracle数据库查询语句中A、B、C、D分别代表&#xff1a; 正确答案&#xff1a; A 2、【单选题】下表为患者缴费记录&#xff0c;现需…

2023跨年烟花3D最炫烟花,html最酷炫动态烟花源码分享,点击即可直接运行

&#x1f4cb; 前言 &#x1f5b1; 博客主页&#xff1a;在下马农的碎碎念✍ 本文由在下马农原创&#xff0c;首发于CSDN&#x1f4c6; 首发时间&#xff1a;2022/12/25&#x1f4c5; 最近更新时间&#xff1a;2022/12/25&#x1f935; 此马非凡马&#xff0c;房星本是星。向前…

lambda表达式,函数式接口,链式编程,Stream流式计算

新时代的程序员&#xff1a;lambda表达式&#xff0c;函数式接口&#xff0c;链式编程&#xff0c;Stream流式计算 函数式接口 函数式接口&#xff1a;只有一个方法的接口(简化编程模型&#xff0c;在新版本框架底层中大量应用&#xff01;) 只要是 函数型接口 就可以使用lambd…

iOS 16.2 在 SwiftUI 子视图中无法关闭弹出的(sheet)导航视图(NavigationView)之解决

问题现象 iOS 16.2 中,若在 SwiftUI 4.0 里弹出(sheet)一个导航视图 A,则不能在 A 的子视图中将 A 关闭(dismiss): 如上图所示:上面的按钮直接放在导航视图 A 中,点击它可以直接关闭 A;而下面的按钮放在一个子视图中,点击它想要关闭 A 却没有任何反应。 那么,该如…

可转债网格交易策略回测

什么是网格交易策略&#xff1a;基于股票波动高抛低吸策略&#xff0c;自动化反复买卖赚取差价。投资者借助条件单&#xff0c;把资金分成多份&#xff0c;从基准价开始&#xff0c;每跌x%就自动买入一份&#xff0c;每涨y%就自动卖掉一份。股价越波动高抛低吸的机会越多 什么…

Java项目:springboot基于java+mysql+springboot的社区养老医疗综合服务平台

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 本项目分为管理员、医生、病人三种角色&#xff0c; 管理员的功能包含如下&#xff1a; 个人信息&#xff1a;个人资料、修改密码 系统管理&…

Python入门学习之字符串与比较运算符

Python字符串 字符串或串(String)是由数字、字母、下划线组成的一串字符。 一般记为 : 1 s"a1a2an"(n>0) 它是编程语言中表示文本的数据类型。 python的字串列表有2种取值顺序: 从左到右索引默认0开始的&#xff0c;最大范围是字符串长度少1从右到左索引默认-1开…

【C++】各种排序涉及到的选择小题合集(每日小细节009)

昨天更新完各种排序之后今天来检验一下是否真的全部掌握了呢&#xff1f; 今天的合集里面包括各种排序的综合选择题和一些解题技巧 花一两分钟看一下真的很有帮助哦 &#xff08;最好能先认真复习一下各种排序&#xff09; 1. 冒泡排序就是相邻元素的两两比较所以依次写出来就…

Java项目:Springboot体育器材管理系统

作者主页&#xff1a;源码空间站2022 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文末获取源码 项目介绍 体育器材管理系统主要包含以下功能&#xff1a; 登录注册&#xff1b; 体育器材管理&#xff1a;显示器材表、显示价目表、显示供应商表&#x…

通达信逐笔接口怎么查询下单明细?

通达信逐笔接口一般会根据实盘交易系统的模式来开发&#xff0c;然后股票量化交易接口端也能很快的获取用户数据&#xff0c;也就是你的账户下单的数据信息&#xff0c;在市场交易期间能实时与多家证券公司对接&#xff0c;实现委托买入卖出操作。那么&#xff0c;像这么方便的…

IO流Properties配置文件

目录 输入流和输出流 File文件增删 常用IO流类及其分类 FileInputStream/FileOutputStream ObjectInputStream/ObjectOutputStream BufferedInputStream/BufferedOutputStream FileReader/FileWriter BufferedReader/BufferedWriter InputStreamReader/InputStreamWri…

为啥devc++程序运行正确返回不为0?而返回了一个特别大的数,详解。

例如运行以下程序: #include #include typedef char ElemType; typedef struct BiTNode{ char data; struct BiTNode *lchild; struct BiTNode *rchild; int DescNum;}BiTNode ,*BiTree; void CreateBiTree(BiTree *T) { char ch; scanf("%c",&ch); if(ch ){…

时序预测 | MATLAB实现IWOA-LSTM和LSTM时间序列预测(改进的鲸鱼算法优化长短期记忆神经网络)

时序预测 | MATLAB实现IWOA-LSTM和LSTM时间序列预测(改进的鲸鱼算法优化长短期记忆神经网络) 目录时序预测 | MATLAB实现IWOA-LSTM和LSTM时间序列预测(改进的鲸鱼算法优化长短期记忆神经网络)预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 MATLAB实现IWOA-LSTM和…

使用React做一个音乐播放器

目录介绍先决条件和设置环境依赖关系播放器.js进口播放和暂停音频使用音频的当前时间和持续时间添加音频时间线输出附加的功能结论介绍 任何正在学习 React 并想使用 React 构建项目的人。有各种博客和文章可以为开发人员指导此类项目。我确实浏览过这些文章&#xff0c;但其中…