我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Javasynchornized与ReentrantLock处理并发出现的错误

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Javasynchornized与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);
		ChangeThread ct = new ChangeThread(stu);
		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);
		ChangeThread ct = new ChangeThread(stu,lock);
		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;
	}
}

此时已经解决了并发错误

到此这篇关于Java synchornized与ReentrantLock处理并发出现的错误的文章就介绍到这了,更多相关Java synchornized与ReentrantLock内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Javasynchornized与ReentrantLock处理并发出现的错误

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Javasynchornized与ReentrantLock处理并发出现的错误

synchronized机制提供了对每个对象相关的隐式监视器锁,并强制所有锁的获取和释放都必须在同一个块结构中。当获取了多个锁时,必须以相反的顺序释放。即synchronized对于锁的释放是隐式的
2023-01-04

Go并发编程中的错误处理与恢复策略

并发编程中错误处理有两种方法:主动错误处理(传播错误)和被动错误处理(错误管道)。恢复策略有两种:恢复(捕获恐慌)和重试(多次执行)。实战案例展示了这四种方法的使用。Go并发编程中的错误处理与恢复策略错误处理在Go并发编程中,错误处理至
Go并发编程中的错误处理与恢复策略
2024-05-11

golang函数错误处理中的并发考虑

在 go 并发环境中,处理错误需要考虑错误共享、错误传递和错误聚合。通过使用错误通道传递和聚合错误,可以确保并发应用程序可靠地处理错误。在 Go 函数错误处理中的并发考虑并发是 Go 编程的一个关键特征,它允许程序员同时执行多个任务。然而
golang函数错误处理中的并发考虑
2024-04-30

错误处理在golang函数并发中的作用

并发函数中的错误处理至关重要,go语言提供了多种方法来处理错误:使用 error 类型存储错误消息。通过函数参数或返回类型传递错误。使用 errgroup 包收集并处理并发函数组的错误。使用自定义错误类型提供更具体的信息。正确处理错误可以确
错误处理在golang函数并发中的作用
2024-04-24

C++ 函数异常与多线程:并发环境下的错误处理

c++++ 中函数异常处理对于多线程环境尤为重要,以确保线程安全和数据完整性。通过 try-catch 语句,可以在出现异常时捕获和处理特定类型的异常,以防止程序崩溃或数据损坏。C++ 函数异常与多线程:并发环境下的错误处理在多线程环境中
C++ 函数异常与多线程:并发环境下的错误处理
2024-05-04

golang中的aws lambda由sqs触发并出现类型错误

php小编百草这次为大家带来了关于golang中的AWS Lambda的问题。在使用AWS SQS触发Lambda函数时,可能会出现类型错误的情况。这个问题可能导致Lambda函数无法正常处理SQS消息,给开发者带来不必要的麻烦。在本文中,
golang中的aws lambda由sqs触发并出现类型错误
2024-02-09

PHP出现500错误时的应急处理方法

PHP出现500错误时的应急处理方法在使用PHP开发网站或应用时,500错误是常见的问题之一。当出现500错误时,意味着服务器无法正确处理请求,用户在浏览网站时会看到“Internal Server Error”的提示。这种错误可能由很多
PHP出现500错误时的应急处理方法
2024-03-07

PHP开发缓存的错误处理与日志记录

PHP开发缓存的错误处理与日志记录,需要具体代码示例缓存是Web开发过程中非常重要的一个概念,可以显著提高网站或应用程序的性能。在大型应用中,缓存甚至可以是性能瓶颈的决定因素。但是,缓存使用不当还会带来一些问题,包括缓存过期、内存泄漏和缓存
PHP开发缓存的错误处理与日志记录
2023-11-07

PHP7下载PDF文件出现错误的处理方式

PHP7下载PDF文件出现错误的处理方式在网站开发中,经常会有需要下载PDF文件的情况。但是有时候在使用PHP7下载PDF文件时会出现一些错误,比如下载的文件无法打开、下载的文件损坏等问题。本文将介绍在PHP7中下载PDF文件出现错误的处
PHP7下载PDF文件出现错误的处理方式
2024-02-29

如何检测和处理并发编程中发生的异常和错误?

并发编程中的异常和错误可导致应用程序故障,可以通过代码审查、单元测试和运行时监视进行检测。处理方法包括异常处理、锁机制、资源管理和恢复操作。实战案例中,共享计数器的并发访问需要适当使用 synchronized 块来防止竞争条件。如何检测和
如何检测和处理并发编程中发生的异常和错误?
2024-05-08

Go语言中如何解决并发请求的错误处理问题?

Go语言中如何解决并发请求的错误处理问题?在开发并发应用时,我们时常需要发送多个并发请求以提高程序的并发性能。然而,当其中一个请求发生错误时,如何有效地捕获和处理这些错误变得非常重要。Go语言提供了一些技术和模式来解决并发请求的错误处理问题
2023-10-22

SQL Server附加数据库时出现错误的处理方法

目录前言一、如何附加数据库?二、无法升级数据库,出现(539类似版本号不匹配)错误解决办法1.常见的无法附加数据库时,出现的错误2.无法升级数据库的解决办法总结前言SQL Server 是数据库软件中比较常见且实用的软件,它的集成度很高,
2022-12-15

SQL Server附加数据库时出现错误的处理方法

通过附加功能添加现成的数据库是非常方便的,然而有时会出现附加数据库失败,下面这篇文章主要给大家介绍了关于SQL Server附加数据库时出现错误的处理方法,需要的朋友可以参考下
2022-12-15

通过golang进行Select Channels Go并发式编程的错误处理方法

在Go并发式编程中,可以使用select语句来同时监听多个通道的数据流动,并根据不同的情况进行处理。当一个或多个通道有数据可读时,select语句会随机选择一个case来执行。在处理错误时,可以将错误信息发送到一个专门的错误通道,并在sel
2023-10-08

基于spring-security出现401 403错误自定义处理的示例分析

这篇文章将为大家详细讲解有关基于spring-security出现401 403错误自定义处理的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。spring-security 401 403错误自定
2023-06-20

SQLServer 错误 41342 系统上的处理器型号不支持创建 construct。 较早的处理器通常会出现此错误。 故障 处理 修复 支持远程

详细信息 Attribute 值 产品名称 SQL Server 事件 ID 41342 事件源 MSSQLSERVER 组件 SQLEngine 符号名称 HK_HW_NOT_SUPPORTED 消息正文 ...
SQLServer 错误 41342 系统上的处理器型号不支持创建 construct。 较早的处理器通常会出现此错误。 故障 处理 修复 支持远程
2023-11-05

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录