多线程04 线程安全问题以及一些简单的解决策略

news2024/11/29 8:54:03

前言

首先我们引入多线程是为了解决多次创建进程和销毁进程带来的巨大开销,线程可以共享内存和硬盘资源等等,这里我们就会想,他们共享这些东西会不会涉及到一些安全问题呢?他们没有独立分配自己的资源是一定会有安全问题的,但是就目前在这个快节奏的社会来说,效率的提升是必然需要的,我们只能去发现和解决这些安全问题,效率第一!!

举例

下面我们给出一段代码,我们从代码的效果和原因来解析这段代码产生的线程安全问题以及解决方案.

package Thread;

public class ThreadDemo17 {
    private static int count = 0;
    private static final Object lock = new Object();


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

我们这里创建两个线程,t1和t2让他们合作完成100000次自增操作,并且阻塞main线程,最后让main线程来收集结果.

下面我给出几次运行产生的结果

运行相同的代码,怎么就一直产生错误的结果,而且错误的还是不一样的呢???

.

下面我给出解析举例

我们观察一下count++这一个自增操作需要几步吧

这里为我们其实只有三步

第一步是取元素,可以看到是getstatic取到count这个变量

第二步是自增1,就是iadd这个操作

第三步是putstatic,气死就是一个保存的操作

iconst_1其实是将1放到栈区的操作数栈顶

由于这个count++的操作是不原子的,所以这里会产生线程安全的问题

下面我们模拟一下不安全的一种用例(以下操作将上述多个操作抽象成取值,自增,保存三个操作)

假设这里只有一次自增,t1中的count先加载为0,此时t2读到的count也是0,t1最后自增保存了一个1,t2进行更新的时候其实更新的也是1,这就会造成了线程不安全问题,最后导致的结果是1而不是2,与我们的理想情况相悖.

导致这个结果的原因有很多,最重要的就是cpu的这种抢占式调度系统,你无法控制cpu先调度哪个线程,执行到哪个命令之后执行其他的命令.

解决方案 

这里我们采用锁来保证线程的安全性,你可以理解为此时张三正在上厕所,咔嚓以下把门锁起来了,这个时候,你再急也进不去,完成不了你的任务,即使此时线程调度到你了,你也只是一个阻塞的状态,无法完成任务

我们使用synchronized关键字来修饰,我们会发现需要一个参数,这个参数其实无论你造一个什么对象都是可以的,只要保证这两个线程的参数是同一个对象即可

举例如下

package Test;

public class ThreadDemo1125 {
    private static int count = 0;
    private static final Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                synchronized (lock){
                    count++;
                }
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                synchronized (lock){
                    count++;
                }
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("count = "+ count);
    }

}

此时线程就是安全的了,但也意味着线程由完全并发式的执行变成了半并发半串行的执行

我们发现代码中,synchronized修饰的代码块是串行执行的,但是其他代码还是并发执行的,所以相较于完全串行使用一个线程来执行还是提升了不少的效率的,下面我们来看代码运行结果

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

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

相关文章

面试常见问题:什么是进程? 什么是线程?进程和线程有什么区别?

1.什么是进程&#xff1f; 进程是操作系统中一个程序在执行过程中的一个实例&#xff0c;每个进程都有自己独立的地址空间&#xff0c;进程间不共享内存。它是程序运行的最小内存单元&#xff1b; 进程特点&#xff1a; 1> 需要占用独立的内存空间&#xff1b; 2>可以并…

基于指数分布算法优化概率神经网络PNN的分类预测 - 附代码

基于指数分布算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于指数分布算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于指数分布优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

C#,《小白学程序》第二十二课:大数的乘法(BigInteger Multiply)

1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary> /// 大数的&#xff08;加减乘除&#xff09;四则运算、阶乘运算 /// 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法 /// </summary> p…

cesium轨迹线(发光轨迹线)

cesium轨迹线(发光轨迹线) 下面有源码 实现思路 使用ellipse方法加载圆型,修改polyline中‘material’方法重写glsl来实现当前效果(cesium版本1.109) 示例代码 index.html <!DOCTYPE html> <html lang="en"><head

C语言指针——从底层原理到应用

参考&#xff1a;C语言指针-从底层原理到花式技巧&#xff0c;用图文和代码帮你讲解透彻 目录 一、前言二、变量与指针的本质1. 内存地址2. 32位与64位系统3. 变量4. 指针变量5. 操作指针变量5.1 指针变量自身的值5.2 获取指针变量所指向的数据5.3 以什么样的数据类型来使用/解…

身在苹果心系Linux:Linux基金会主管在开源峰会使用macOS做演示

2017开源峰会正在进行中&#xff0c;来自全球各地的Linux大厂和开源大厂纷纷涌向洛杉矶参加这次活动。 Linux基金会执行董事Jim Zemlin在推文中宣布&#xff1a;2017年是属于Linux桌面的一年&#xff01; ▲图片来源&#xff1a;itsfoss.com 然而&#xff0c;据外媒itsfoss报…

微机课设--汇编语言在51单片机上写一个四位十进制加法器

代码如下 KEYVAL EQU 30HKEYTM EQU 31HKEYSCAN EQU 32HDAT EQU 33HSCANLED EQU 37HS_DAT EQU 38HD_DAT EQU 39HR_DATL EQU 3AHR_DATH EQU 3BH CALFLAG EQU 3CHFLAG BIT 00HORG 0000HLJMP MAINORG 000BHLJMP T0ISRORG 0030HMAIN:MOV SP,#5FHMOV TMOD,#01HMOV TH0,#0D8HMOV TL0,…

FreeRTOS入门教程(任务通知)

文章目录 前言一、什么是任务通知二、任务通知和队列&#xff0c;信号量的区别三、任务通知的优点和缺点1.优点2.缺点 四、任务状态和通知值五、任务通知相关的函数发出通知取出通知 六、任务通知具体使用1.实现轻量级信号量二进制信号量计数型信号量 2.实现轻量级队列 总结 前…

Guitar Pro8.0.2吉他编曲软件 吉他打谱软件 吉他作曲软件

Guitar Pro8.0.2在音乐的大舞台上&#xff0c;谁不想成为一位吉他弹奏大师呢&#xff1f;但在现实中&#xff0c;学吉他并非一蹴而就&#xff0c;许多小伙伴都因为吉他的上手难度而被浇灭学习的热情。然而&#xff0c;这里有一款神奇的软件&#xff0c;叫做&#xff0c;它就像是…

C++双指针算法:统计点对的数目

本周推荐阅读 C二分算法&#xff1a;得到子序列的最少操作次数 本题其它解法 C二分查找&#xff1a;统计点对的数目 题目 给你一个无向图&#xff0c;无向图由整数 n &#xff0c;表示图中节点的数目&#xff0c;和 edges 组成&#xff0c;其中 edges[i] [ui, vi] 表示 u…

IO和NIO的区别 BIO,NIO,AIO 有什么区别? Files的常用方法都有哪些?

文章目录 IO和NIO的区别BIO,NIO,AIO 有什么区别?Files的常用方法都有哪些&#xff1f; 今天来对java中的io, nio, bio, aio进行了解&#xff0c;有何区别。 IO和NIO的区别 NIO与IO区别 IO是面向流的&#xff0c;NIO是面向缓冲区的Java IO面向流意味着每次从流中读一个或多个字…

【开源】基于Vue.js的快乐贩卖馆管理系统

项目编号&#xff1a; S 064 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S064&#xff0c;文末获取源码。} 项目编号&#xff1a;S064&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 搞笑视频模块2.3 视…

Java核心知识点整理大全15-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…

steam搬砖还能做吗?CSGO饰品未来走势如何?

steam/csgo搬砖项目真能月入过万吗&#xff1f;到底真的假的&#xff1f; 如何看待CSGO饰品市场的整体走向&#xff1f; 从整体来说&#xff0c;CSGO的饰品市场与规模肯定会持续不断的上升&#xff0c;大盘不会发生特别大的波动&#xff0c;目前处于稳定期&#xff01;&#x…

elasticsearc DSL查询文档

文章目录 DSL查询文档DSL查询分类全文检索查询使用场景基本语法示例 精准查询term查询range查询总结 地理坐标查询矩形范围查询附近查询 复合查询相关性算分算分函数查询1&#xff09;语法说明2&#xff09;示例3&#xff09;小结 布尔查询1&#xff09;语法示例&#xff1a;2&…

C语言公交车之谜(ZZULIOJ1232:公交车之谜)

题目描述 听说郑州紫荆山公园有英语口语角&#xff0c;还有很多外国人呢。为了和老外对上几句&#xff0c;这周六早晨birdfly拉上同伴早早的就坐上了72路公交从学校向紫荆山进发。一路上没事干&#xff0c;birdfly开始思考一个问题。 从学校到紫荆山公园共有n(1<n<20)站路…

LeetCode Hot100 33.搜索旋转排序数组

题目&#xff1a; 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nu…

Docker Swarm总结+基础、集群搭建维护、安全以及集群容灾(1/4)

博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码下载地址&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb;…

C#,《小白学程序》第二十课:大数的加法(BigInteger Add)

大数的&#xff08;加减乘除&#xff09;四则运算、阶乘运算。 乘法计算包括小学生算法、Karatsuba和Toom-Cook3算法。 重复了部分 19 课的代码。 1 文本格式 using System; using System.Linq; using System.Text; using System.Collections.Generic; /// <summary>…

网络视频播放卡顿原因分析

一、问题描述 某项目通过拉摄像机rtsp流转rtmp/http-flv/ws-flv的方案&#xff0c;使用户可以在网页中观看摄像机的视频画面。在 观看视频时偶发出现卡顿现象。 二、卡顿现象分析和解决 此问题涉及的原因较多&#xff0c;所以得考虑各环节的问题可能性&#xff0c;并根据现场实…