JavaEE初阶之线程安全(一)

 

目录

题外话

正题

1.线程调度是随机的

2.修改共享数据

知识点

线程同步机制

线程异步机制

举例说明

synchronized()

知识点

举例说明

举例代码详解

死锁

举个例子:

代码

小结


题外话

这两天忽冷忽热的感冒了,昨天状态特别不好断更了一天,今天继续加油!

我会把所有知识点放在每个小标题最前面,省的大家东找一个西找一个,大家可以先略微看看知识点,把文章看一遍回过头再看知识点,就有种豁然开朗的感觉

然后我比较喜欢用费曼学习法,大家有兴趣可以查查

这里简单说下费曼学习法,大家应该也或多或少知道这个,大家在跟着视频学习的时候,可以附和视频中的老师,或者试着对话,再或者遇到知识点,可以用给别人讲课的方式,把知识点说出来,这样确实很温故知新

就是在宿舍自言自语,自我对话会被别人当成傻子,怕社死的还是慎重考虑

我觉得做笔记也很关键,我从开始学javase,就开始把所有java知识点都放在了一个word文档里

复习起来也很方便,不需要再去翻找视频什么的费时费力,(如下图)

正题

我们先说说引发线程安全的因素

1.线程调度是随机的

大家都知道,JVM中线程是抢占式调度,所有线程去抢占cup的资源,线程抢的资源越多,执行该线程的速度也会越快

我们要做的是在写代码的时候,使多线程让任意执行顺序下都可以顺利执行

2.修改共享数据

知识点

一.先提出两个概念

我们把线程排队执行(线程一个一个执行),叫做;线程同步机制

而抢占式执行(多个线程一起执行),叫做;线程异步机制

先说说线程同步机制和线程异步机制的优缺点

线程同步机制

优点:可以保证数据安全问题

缺点:因为排队执行,导致效率变低,而且利用synchronized也会产生一些问题(如死锁等等)

线程异步机制

优点:多线程抢占式执行,效率很高

缺点:因为线程各自独立运行,互不影响,修改共享数据会产生数据错乱问题

二.再说说在java中什么数据会产生修改共享数据的问题

1.一般情况下:局部变量不存在线程安全问题。(尤其是基本数据类型不存在线程安全问题,因为它们在栈中,栈不共享数据,如果是引用数据类型,就另说了)

2.实例变量可能存在线程安全问题,实例变量在堆中,堆是多线程共享的。

3.静态变量也可能存在线程安全问题,静态变量在堆中,堆是多线程共享的

举例说明

先让大家更清晰理解修改共享数据会产生什么问题

比如一个银行账户被张三和李四两个人使用,两个人都把这张卡绑定支付,两个人都想取钱出来花,(如下图)

首先,银行会各自读取银行卡余额,然后再各自取钱,按照JVM中线程抢占式调用资源,

我们不知道张三取钱的时候,李四会不会才进行到获取银行卡余额这种情况,如果发生了这种情况,就会出现银行卡余额数据异常(当然,银行肯定非常安全,这种问题早就被解决了)

上述问题就是修改共享数据

所以面对这种问题,我们并不需要抢占式执行,而是需要排队执行,给张三取完钱,再去执行李四取钱的操作.

我们就需要synchronized()

synchronized()

知识点

1.线程同步的本质是:线程排队执行就是同步机制。

2. 语法格式:

synchronized(必须是需要排队的这几个线程共享的对象){

需要同步的代码

}

“必须是需要排队的这几个线程其享的对象”这个必须选对,

这个如果选错了,可能会无故增加同步的线程数量,导致效率降低。

3.可以给一块代码加锁,也可以对实例方法,静态方法加锁

加锁并不是一个很好的选择

加锁优缺点

优点:防止修改共享数据造成数据错乱

缺点:1.加锁的位置需要很慎重考虑

    因为有些线程需要修改共享数据,而有些线程不需要修改共享数据,如果把这种数据全部加锁,就会产生效率问题

        2.加锁占用资源比较大

        3.当我们写的代码越来越多,如果滥用锁的话会产生死锁等等一系列问题,导致效率很低

举例说明

synchronized()就是锁,大家可以理解为上厕所

一套屋子只有一个厕所,有人进去了,其他人只能等他出来才能进去

通过一段代码,让大家更清晰理解上锁会怎么样

这里代码没有上锁,让大家看看修改共享数据会造成什么后果

举例代码详解

以下是实现两个线程各自执行一万次count累加

public class ThreadDemo14 {static int count=0;public  void add(){count++;}public static void main(String[] args) throws InterruptedException {ThreadDemo14 t=new ThreadDemo14();Thread t1=new Thread(()->{for (int i = 0; i < 10000; i++) {t.add();}});Thread t2=new Thread(()->{for (int i = 0; i < 10000; i++) {t.add();}});t1.start();t2.start();Thread.sleep(1000);System.out.println(count);}}
正常来说我们理想状态打印出的count应该是20000,但是修改共享数据会发生数据异常(如下图)这次大家看好我加锁后的代码
public class ThreadDemo14 {static int count=0;
//直接给add方法加锁public synchronized void add(){count++;}public static void main(String[] args) throws InterruptedException {ThreadDemo14 t=new ThreadDemo14();Thread t1=new Thread(()->{for (int i = 0; i < 10000; i++) {t.add();}});Thread t2=new Thread(()->{for (int i = 0; i < 10000; i++) {t.add();}});t1.start();t2.start();Thread.sleep(1000);System.out.println(count);}}

而这次运行结果和咱们理想结果一样

 

 

我是在add方法上直接加锁了,当然也可以在方法里加锁,synronized(this){代码块}这种形式即可

死锁

我们再说一下死锁的问题,其实死锁就是互相矛盾

举个例子:

小明在厕所1,厕所1只能洗手,一个厕所只能进入一个人

小红在厕所2,厕所2只能蹲坑,一个厕所只能进入一个人

小明洗完手想去蹲坑,而小红蹲完坑想去洗手,但是一个厕所只能进入一个人,这样他们永远不能走出自己所在的厕所,如下图

让大家看看代码,或许就明白了!

代码
public class ThreadDemo15 {public static void main(String[] args) {
//创建两个Oberject对象o1,o2Object o1=new Object();Object o2=new Object();
//建立两个线程t1,t2Thread t1=new MyThread01(o1,o2);Thread t2=new MyThread01(o1,o2);
//t1命名t1,t2命名t2t1.setName("t1");t2.setName("t2");t1.start();t2.start();}
}
//创建类继承Thread
class MyThread01 extends Thread
{
//创建私密变量o1,o2private Object o1;private Object o2;
//创建构造方法public MyThread01(Object o1,Object o2){this.o1=o1;this.o2=o2;}
//重写run方法@Overridepublic void run() {
//如果线程名字等于t1if ("t1".equals(Thread.currentThread().getName())){
//进入o1锁synchronized (o1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("解开了");
//进入o2锁synchronized (o2){}}}
//如果线程名字和t2一样else if ("t2".equals(Thread.currentThread().getName())){
//进入o2锁synchronized (o2){ try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("解开了");
//进入o1锁synchronized (o1){}}}}
}

当我们运行的时候就会发现,t1和t2都进入了锁中,但是永远不会结束进程,永远不会报错,就这样一直锁着,如下图

所以说还是需要好好掌握一下synchronized()的使用方式

小结

写完这篇有点晚了,但今天收获还是很大的,喜欢的朋友多多支持一下吧!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

远控桌面多任务并发文件保密传输

远程桌面文件传输是一个重要的功能&#xff0c;大多数远控都是用的桌面程序模式&#xff0c;利用系统自带复制粘贴拖拽文件拷贝功能&#xff0c;做一个ole调用对接&#xff0c;可以将很多控制权交给操作系统。 但我做的是浏览器版&#xff0c;浏览器是沙盒原理&#xff0c;为了…

LeetCode 738. 单调递增的数字

当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。 给定一个整数 n &#xff0c;返回 小于或等于 n 的最大数字&#xff0c;且数字呈 单调递增 。 示例 1: 输入: n 10 输出: 9示例 2: 输入: n 1234 输出: 1234示例 3: 输入…

交通标志识别项目 | 基于Tensorflow+SSD实现道路交通标志识别

项目应用场景 面向智能驾驶或自动驾驶场景道路道路交通标志的识别&#xff0c;在交通标志识别的基础上为下一步的智能决策提供前提 项目效果&#xff1a; 项目细节 > 具体参见项目 README.md (1) 安装依赖 Python3.5、TensorFlow v0.12.0、Pickle、OpenCV-Python、Matplotl…

python笔记(9)Dictionary(字典)

目录 创建字典 取值 修改字典 删除 内置函数和方法 创建字典 字典键值和value用&#xff1a;隔开&#xff0c;键值是不可变的&#xff0c;而且必须是唯一的&#xff0c;值可以变&#xff0c;可以是任意类型 dict {key1 : value1, key2 : value2 } 1&#xff09;不允许同…

【面试八股总结】传输控制协议TCP(一)

一、什么是TCP协议 TCP是传输控制协议Transmission Control Protocol TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。 面向连接的&#xff1a;每条TCP连接杜只能有两个端点&#xff0c;每一条TCP连接只能是点对点的&#xff08;一对一&#xff09;可靠的&#xff1a…

学习Linux推荐的书籍

我记得有人曾经说过&#xff0c;征服一个男人最好的途径就是抓住他的胃。 ‍‍‍‍ 学习Linux&#xff0c;最重要的就是要先搞懂Linux是啥&#xff0c;有啥&#xff0c;为啥&#xff1f;‍‍‍‍‍‍‍‍‍‍‍‍‍ 所以&#xff0c;我推荐的第一本书就是-《Unix编程艺术》。…

6000000IOPS!FASS×kunpeng920全新突破

实测数据详见下文 网络环境 前端和后端网均采用100GE网络&#xff0c;管理网采用1Gbps以太网。 前端网和后端网通过不同网段隔离&#xff0c;与管理网物理隔离。 软硬件配置 存储端配置&#xff1a; 客户端配置&#xff1a; 软件配置&#xff1a; 存储集群配置&#xff1a; …

unity双层滑动实现

实现功能&#xff1a; 当滑动列表中内容处于顶端的时候&#xff0c;向上滑动优先滑动整个滑动列表&#xff0c;当滑动列表移动到设置位置&#xff0c;即设定的最高处时&#xff0c;继续移动列表内内容。向下移动亦然&#xff0c;当内容处于滑动列表顶端时&#xff0c;移动整个滑…

matlab——基于三维激光扫描点云的树冠体积计算方法

目录 一、算法原理1、原理概述2、参考文献二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 1、原理概述 针对树冠形状不规则,树冠体积难以测量和计算的问题,提出一种基于三…

docker-compse安装es(包括IK分词器扩展)、kibana、libreoffice

Kibana是一个开源的分析与可视化平台&#xff0c;设计出来用于和Elasticsearch一起使用的。你可以用kibana搜索、查看存放在Elasticsearch中的数据。 Kibana与Elasticsearch的交互方式是各种不同的图表、表格、地图等&#xff0c;直观的展示数据&#xff0c;从而达到高级的数据…

算法题->有效的三角形个数C语言和JAVA版本双指针解法

有效的三角形个数C语言和JAVA版本双指针解法 力扣链接:https://leetcode.cn/problems/valid-triangle-number/description/ 题目描述: 题意:给你一个数组,通过数组中的三个值进行组成有效三角形,最后返回有效三角形个数 例子: 由例子可知,不同下标的一个值和相同两个值组成…

GPT3, llama2, InternLM2技术报告对比

GPT3&#xff08;September 22, 2020&#xff09;是大语言应用的一个milestone级别的作品&#xff0c;Llama2&#xff08;February 2023&#xff09;则是目前开源大模型中最有影响力的作品&#xff0c;InternLM2&#xff08;2023.09.20&#xff09;则是中文比较有影响力的作品。…

【漏洞复现】HIKVISION 联网网关userInfoData.php 接口处敏感信息泄露漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

前端、后端上传文件到OSS,简明记录

前端、后端上传文件到OSS&#xff0c;简明记录 上传文件到oss的方式&#xff1a; **后端上传&#xff1a;**文件先要从页面上传到后端存起来&#xff0c;再通过后端发送到oss&#xff0c;然后后端将存起来的文件删除&#xff08;当然可以不删&#xff09;。 **前端上传&…

ArcGIS Pro怎么进行挖填方计算

在工程实施之前&#xff0c;我们需要充分利用地形&#xff0c;结合实际因素&#xff0c;通过挖填方计算项目的标高&#xff0c;以达到合理控制成本的目的&#xff0c;这里为大家介绍一下ArcGIS Pro中挖填方计算的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的…

SpringCloud学习(1)-consul

consul下载安装及使用 1.consul简介 Consul是一种开源的、分布式的服务发现和配置管理工具&#xff0c;能够帮助开发人员构建和管理现代化的分布式系统。它提供了一套完整的功能&#xff0c;包括服务注册与发现、健康检查、KV存储、多数据中心支持等&#xff0c;可以帮助开发人…

linux shell命令(进程管理、用户管理)

一、进程的概念 主要有两点&#xff1a; 1.进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08;text region&#xff09;、数据区域&#xff08;data region&#xff09;和堆栈&#xff08;stack region&#xff09;…

用Servlet实现一个简单的表白墙

1. 准备工作 创建项目,引入依赖...... 将静态页面放到项目中(放在webapp目录下): 当前,这个表白墙页面,已经可以输入内容,点击提交之后也能显示内容,后续后端要做的工作即: ①存档 用户点提交的时候,把刚才输入的内容通过网络传输给服务器,由服务器保存这个数据. ②读档 …

计算机网络(第八版)-第1章课后习题参考答案

计算机网络(第八版)-第1章课后习题参考答案 本文是对自己之前文章的格式化&#xff1a;https://blog.csdn.net/qq_46396470/article/details/132788972?spm1001.2014.3001.5502 T1-01 计算机网络向用户可以提供哪些服务&#xff1f; 连通性和共享 &#xff0c;例如音频&…