使用synchornized和ReentrantLock来解决并发错误

news2024/9/25 13:20:57

文章目录

    • 什么是并发错误?
    • 并发错误是如何产生的?
    • 演示并发错误
    • 如何解决并发错误
      • 使用synchornized解决并发错误
      • 使用ReentrantLock解决并发错误

什么是并发错误?

多个线程共享操作同一个对象的时候,线程体当中连续的多行操作未必能够连续执行 很可能操作只完成了一部分,时间片突然耗尽,此时,另一个线程抢到时间片,直接拿走并访问了操作不完整的数据(操作不完整的数据,从逻辑上讲是错误数据)。

并发错误是如何产生的?

  • 根本原因: 多个线程共享操作同一份数据

  • 直接原因: 线程体当中连续的多行语句,未必能够连续执行,很可能操作只完成了一半 时间片突然耗尽。
    此时另一个线程刚好抢到时间片,直接拿走了操作不完整的数据 - 错误数据。

  • 导火索: 时间片突然耗尽

演示并发错误

public class TestConcurrentError{
	public static void main(String[] args){
		Student stu = new Student("张朝伟","先生");
		PrintThread pt = new PrintThread(stu);
		ChangeThread ct = new ChangeThread(stu);
		pt.start();
		ct.start();
	}
}
class PrintThread extends Thread{
	Student stu;
	public PrintThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		while(true){
			System.out.println(stu);
		}
	}
}
class ChangeThread extends Thread{
	Student stu;
	public ChangeThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		boolean isOkay = true;
		while(true){
				if(isOkay){ 
					stu.name = "张曼玉";
					stu.gender = "女士";
				}else{ 
					stu.name = "梁朝伟";
					stu.gender = "先生";
				}
				isOkay = !isOkay;
		}
	}
}

class Student{
	String name;
	String gender;//性别
	public Student(String name,String gender){
		this.name = name;
		this.gender = gender;
	}
	@Override
	public String toString(){
		return name + " : " + gender;
	}
}

我们看运行结果发现一个非常严重的问题
在这里插入图片描述

我们的代码从来没有写过将梁朝伟赋值为女士,也没有写过将张曼玉赋值为女士我们的程序为什么会出现这样的情况 ?

线程体当中连续的多行操作未必能够连续执行 假如我们将stu的名字赋值为梁朝伟,此时CPU时间片耗尽了,另一个打印的线程抢到时间片的情况下 就会将原来的正确的值改为错误的数据 从而产生并发错误。

如何解决并发错误

要想解决并发错误加锁是必须的

使用synchornized解决并发错误

synchronize语法级别的加锁也叫​ 互斥锁=互斥标记=锁标记=锁旗标=监视器= Monitor

synchornized修饰代码块

synchronized(临界资源){
	需要连续执行的操作
}

synchornized修饰整个方法

public synchronized void add(){
  
}
//等价于
public void add(){
	synchronized(){
	}
}

注意:即便synchronized加在方法上,其实还是对对象进行加锁,而且锁的是调用方法的那个对象Java世界里只有每个对象才有锁标记,所以加锁只能对对象加锁。

public class TestConcurrentError{
	public static void main(String[] args){
		Student stu = new Student("张朝伟","先生");//勋勋
		PrintThread pt = new PrintThread(stu);//A女孩
		ChangeThread ct = new ChangeThread(stu);//C女孩
		pt.start();
		ct.start();
	}
}
//1st.用于打印显示数据的线程 => 勋勋
class PrintThread extends Thread{
	Student stu;
	public PrintThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		while(true){
			synchronized(stu){//我们要对一组连续的操作加锁 不要对所有操作加锁
							  //我们去厕所 只是锁一次上厕所的过程 不要一辈子死在厕所里
				System.out.println(stu);
			}
		}
	}
}
class ChangeThread extends Thread{
	Student stu;
	public ChangeThread(Student stu){
		this.stu = stu;
	}
	@Override
	public void run(){
		boolean isOkay = true;
		while(true){
			synchronized(stu){
				if(isOkay){ //梁朝伟 先生
					stu.name = "张曼玉";//张曼玉 先生 |~
					stu.gender = "女士";//张曼玉 女士 |~
				}else{ //张曼玉 女士
					stu.name = "梁朝伟";//梁朝伟 女士 |~
					stu.gender = "先生";//梁朝伟 先生
				}
				isOkay = !isOkay;
			}
		}
	}
}

class Student{
	String name;
	String gender;//性别
	public Student(String name,String gender){
		this.name = name;
		this.gender = gender;
	}
	@Override
	public String toString(){
		return name + " : " + gender;
	}
}

使用ReentrantLock解决并发错误

java.util.concurrent.locks.ReentrantLock(jdk 5.0开始):java包的工具包的并发包的 可重入锁
ReentrantLock :lock(加锁) unlock(解锁):放在finally{}中
ReentrantLock可以在构造方法中传公平锁和非公平锁(公平与否针对第一个先来的线程而言)
公平锁:new Reetrantlock(true);

  • JDK6.0之前这个Lock的机制比synchronized效率高很多 JDK6.0开始
  • 重新对synchronized修改了底层实现,加入了一堆新的概念 (偏向锁 轻量级锁 锁的自旋机制) 从JDK6.0开始 synchronized 跟 Lock性能上不相上下
import java.util.concurrent.locks.*;
public class TestConcurrentErrorWithLock{
	public static void main(String[] args){
		Lock lock = new ReentrantLock();
		Student stu = new Student("张朝伟","先生");//勋勋
		PrintThread pt = new PrintThread(stu,lock);//A女孩
		ChangeThread ct = new ChangeThread(stu,lock);//C女孩
		pt.start();
		ct.start();
	}
}
//1st.用于打印显示数据的线程 => 勋勋
class PrintThread extends Thread{
	Student stu;
	Lock lock;
	public PrintThread(Student stu,Lock lock){
		this.stu = stu;
		this.lock = lock;
	}
	@Override
	public void run(){
		while(true){
			lock.lock();//锁 既是一个名词 又是一个动词
			try{
			//synchronized(stu){//我们要对一组连续的操作加锁 不要对所有操作加锁
							  //我们去厕所 只是锁一次上厕所的过程 不要一辈子死在厕所里
				System.out.println(stu);
			//}
			}finally{
				lock.unlock();
			}
		}
	}
}
class ChangeThread extends Thread{
	Student stu;
	Lock lock;
	public ChangeThread(Student stu,Lock lock){
		this.stu = stu;
		this.lock = lock;
	}
	@Override
	public void run(){
		boolean isOkay = true;
		while(true){
			//synchronized(stu){
				lock.lock();
				try{
					if(isOkay){ //梁朝伟 先生
						stu.name = "张曼玉";//张曼玉 先生 |~
						stu.gender = "女士";//张曼玉 女士 |~
					}else{ //张曼玉 女士
						stu.name = "梁朝伟";//梁朝伟 女士 |~
						stu.gender = "先生";//梁朝伟 先生
					}
					isOkay = !isOkay;
				}finally{
					lock.unlock();
				}
			//}
		}
	}
}

class Student{
	String name;
	String gender;//性别
	public Student(String name,String gender){
		this.name = name;
		this.gender = gender;
	}
	@Override
	public String toString(){
		return name + " : " + gender;
	}
}

在这里插入图片描述

此时已经解决了并发错误

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

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

相关文章

下个文档还要马内?还好我会Python,教大家来一手强制复制粘贴

前因后果 公司有人阳了,今天在家上班,突然小姨子就问我有没有baidu文库会员,想下载点东西,我心想这还要会员?用Python不是分分钟的事情! 然后我非常自信的告诉她不用会员随便下载,结果她顺势想…

10两级电力市场环境下计及风险的省间交易商最优购电模型

参考文章: 两级电力市场环境下计及风险的省间交易商最优购电模型—郭立邦(电网技术2019) 主要内容: 为进一步推动电力市场建设,促进电力资源大范围优化配置,我国正逐步建成包含省间与省内电力交易的两级…

齿轮魔方、五阶齿轮魔方

齿轮魔方 1,魔方三要素 (1)组成部件 部件和三阶魔方完全对应,但每个棱块的朝向不止2种,而是有6种。 (2)可执行操作 只有3种操作,即上下层同时旋转180度、左右180度、前后180度。…

一文助你快速理解Cookie,Session,Token的区别

目录 一、Cookie简介 1.1.cookie定义 1.2.cookie鉴权原理 1.3.cookie的分类 二、Session简介 2.1.session的定义 2.2.session会话机制 2.3.Session 的缺点 三、cookie与session区别 3.1.存储位置 3.2.安全性 3.3.占用服务器资源 3.4.存储空间 3.5.存储类型 3.6.…

编程入门宝典,刚开始学习编程新手必看的5点建议!

编程就像围城,城里的人想出去,城外的人想进来。 对于零基础的小白,要杀入代码的战场需要准备好哪些东西呢?最帅的萌宝在此给大家分享5点建议。 1、选择编程语言 编程首要还是选择好适合自己的语言。 编程语言有:C/C、java、VB、P…

零基础学Python:编程规范

1. 注释 python注释也有自己的规范,在文章中会介绍到。注释可以起到一个备注的作用,团队合作的时候,个人编写的代码经常会被多人调用,为了让别人能更容易理解代码的通途,使用注释是非常有效的。 在说规范之前我们有必…

微服务综合部署——SpringBoot项目制作Docker镜像注册在Zookeeper并利用K8S技术部署

一、如果你要从头开发一个基于微服务架构的项目,项目中的服务最终要部署在k8s管理的镜像环境中,你认为应如何创建项目?与本次实验过程相比,哪些改进可以让开发更加合理高效? 第一步:搭建项目并制作合适的j…

回溯算法总结

目录介绍伪代码例题:解释:回溯算法中的优化去重伪代码剪枝常见题型子集例题全排列例题参考资料介绍 递归(DFS)是一个劲的往某一个方向搜索,而回溯算法建立在 DFS 基础之上的,但不同的是在搜索过程中,达到结束条件后&am…

SAP ABAP 扫描 ABAP 源代码(RS_ABAP_SOURCE_SCAN)

SAP ABAP 扫描 ABAP 源代码(RS_ABAP_SOURCE_SCAN) 引言: RS_ABAP_SOURCE_SCAN 是一个 SAP 标准 ABAP 报表程序,通过输入字符串文本,扫描 ABAP 源代码,列示查找字符串在 ABAP 源代码中出现的位置清单。本文…

20行python代码的入门级小游戏

0、背景: 作为一个python小白,今天从菜鸟教程上看了一些python的教程,看到了python的一些语法,对比起来(有其他语言功底),感觉还是非常有趣,就随手添了一点内容,改了一个…

【车载开发系列】CAN总线通信---总线报文格式

【车载开发系列】CAN总线通信—总线报文格式 CAN总线通信---总线报文格式【车载开发系列】CAN总线通信---总线报文格式一.什么是ISO15765二.ISO15765的目的三.单帧传输的概念四.多帧传输的概念五.诊断报文格式1)首帧FF2)连续帧CF3)流控帧FC4&…

【JavaScript】for循环

文章目录for循环案例1:两数相加案例2:绘制九九乘法表案例3:水仙花数案例4:绘制菱形案例5:计算表达式结果break和continue图片切换效果案例(轮播图结构)一、JavaScript代码二、HTML结构和CSS样式…

基于java+springmvc+mybatis+vue+mysql的演出道具租赁管理系统

项目介绍 前端页面: 功能:首页、道具出租、公告资讯、个人中心、后台管理 管理员后台页面: 功能:首页、个人中心、用户管理、商家管理、道具类型管理、道具出租管理、租赁订单管理、道具归还管理、我的收藏管理、系统管理 用户…

密西根大学张阳实验室郑伟博士在CASP15蛋白质结构预测大赛中斩获多项冠军

简报:在有着蛋白质结构预测领域奥林匹克竞赛之称的最新一届CASP比赛中(CASP15),密西根大学张阳教授和Peter Freddolino教授实验室的郑伟博士在多个比赛项目中获得冠军。其中D-I-TASSER算法(参赛名:“UM-TBM…

nodejs银行取号系统vue

目 录 1绪论 1 1.1项目研究的背景 1 1.2开发意义 1 1.3项目研究现状及内容 5 1.4论文结构 5 2开发技术介绍 7 2.1 B/S架构 7 2.2 MySQL 介绍 7 2.3 MySQL环境配置 7 3系统分析 9 3.1可行性分析 9 3.1.1技术可行性 9 3.1.2经济可行性 …

学会4种方法,掌握端到端测试处理数据..

推荐阅读: [内部资源] 想拿年薪30W的软件测试人员,这份资料必须领取~ Python自动化测试全栈性能测试全栈,挑战年薪40W 对Web应用程序运行自动化的端到端测试时,最常见的问题之一是如何处理测试数据。端到端测试通常会在通过应用…

授权服务器搭建以及授权码模式

前面的 GitHub 授权登录主要向大家展示了 OAuth2 中客户端的工作模式。对于大部分的开发者而言,日常接触到的 OAuth2 都是开发客户端,例如接入 QQ 登录、接入微信登录等。不过也有少量场景,可能需要开发者提供授权服务器与资源服务器&#xf…

Spring MVC【创建与使用】

Spring MVC【创建与使用】🍎一.Spring MVC介绍🍒1.1 什么是SpringMVC?🍒1.2 MVC 定义🍒1.3 Spring MVC 与 MVC 的区别🍒1.4 Spring MVC的基本功能🍎二. Spring MVC项目的创建🍒2.1 Spring MVC …

代码随想录DAY51 | 309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费

文章目录309.最佳买卖股票时机含冷冻期714.买卖股票的最佳时机含手续费309.最佳买卖股票时机含冷冻期 文章讲解:代码随想录 (programmercarl.com) 题目链接:309. 最佳买卖股票时机含冷冻期 - 力扣(LeetCode) 题目: …

Efficientdet源码详解

1.参数配置 最重要的参数配置如下 -p:配置文件,需要在project文件夹下新建配置文件-c:efficientdet的版本,efficientdet B0-B7-n:windows为0,linix根据自己的需求修改--batch_size:batch大小--data_path:数据集路径-p data --batch_size 16 其中&…