Java高并发系列: 使用wait - notify实现高效异步方法

news2024/9/24 9:26:08

1. 背景

在项目开发中, 通常会有异步执行操作, 例如: 提交一个异步清空一系列数据库中ID = ${_id} 的记录, 这个时候通常的做法是主线程将任务添加到一个异步队列中, 后台维护一个线程不断地循环扫描这个队列, 如果有需要执行的任务, 则执行相应的逻辑. 如下图所示:
在这里插入图片描述

2. 一个简单的异步执行方法

代码实现如下所示:

public class AsyncExecutor {

    private static final Deque<AsyncTaskEntity> taskQueue = new ConcurrentLinkedDeque<>();

    public AsyncExecutor() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    if (taskQueue.isEmpty()) {
                    	// 休眠50毫秒
                        ThreadUtil.sleep(50);
                        continue;
                    }
                    AsyncTaskEntity entity = taskQueue.pollFirst();
                    execute(entity);
                } catch (Exception e) {
                    LOGGER.error("异步执行任务出现异常!", e);
                }
            }
        });
        thread.setName("异步任务执行器");
        thread.start();
        System.out.println("analysis异步队列任务启动完成!");
    }

    public static <T> void asyncExecute(AsyncTaskEntity<T> entity) {
        taskQueue.push(entity);
    }
}

/**
 * 队列中任务对象封装
 */
@Data
public class AsyncTaskEntity <T>{
    // 消费的参数
    private T param;

	public AsyncTaskEntity(T param){
		this.param = param;
	}
}

有了上面的异步执行器之后, 这里我们写一个main方法, 在main方法中通过异步的方式执行一些任务:

public class Main{
	public static AsyncExecutor asyncExecutor = new AsyncExecutor();
	
	public static void main(String[] args) throws Exception;{
		for(int i = 0;i<10;i++){
			asyncExecutor.asyncExecute(new AsyncTaskEntity<Integer>(i));
		}
		Thread.sleep(10_000);
	}
}

到此为止一个简单清晰的异步调用逻辑就已经写完了. 但是现在不得不考虑一个事情, 异步线程中while(true)会一直空转, 即使没有任务。因此下面我们使用wait - notify进行优化

3. 优化版本1 - 使用wait - notify

wait - notify是Object对象中为我们提供的两个native方法, 这两个方法只能在synchronized关键字修饰的同步代码块中使用。Thread.sleep()方法不会释放锁,wait()方法会释放锁,直到被其他线程notify之后,才会重新获得锁。我们对上述异步队列进行改造:

public class AsyncExecutor {

    private static final Deque<AsyncTaskEntity> taskQueue = new LinkedBlockingDeque<>();

    public AsyncExecutor() {
        Thread thread = new Thread(() -> {
            while (true) {
            	synchronized(this){
	                try {
	                    if (taskQueue.isEmpty()) {
	                        this.wait();
	                    }
	                    AsyncTaskEntity entity = taskQueue.pollFirst();
	                    execute(entity);
	                } catch (Exception e) {
	                    LOGGER.error("异步执行任务出现异常!", e);
	                }
	            }
            }
        });
        thread.setName("异步任务执行器");
        thread.start();
        System.out.println("analysis异步队列任务启动完成!");
    }

    public synchronized <T> void asyncExecute(AsyncTaskEntity<T> entity) {
        taskQueue.push(entity);
        this.notify();
    }
}

经过上面改造之后,当后台队列中任务为空时,轮训扫描线程就会进入到this.wait()逻辑,此时会释放synchronized获取到的this锁。因此调用asyncExecute()方法会正常的获取到this锁。当push数据之后,执行了notify,便会唤醒一个当前this上正在wait()的线程。这种方式就避免了占用资源始终空转的问题。

其实结合线程的三种核心状态可以更好的理解,当调用wait()方法时,该线程会放弃CPU执行权,进入到阻塞状态,直到被其他线程唤醒(notify())。

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

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

相关文章

Discourse 附件无法显示的跟进

今天登录表以后&#xff0c;发现数据又被清理了部分。 然后我们又重新使用 SQL 导入了数据。 这个让我们感觉 Discourse 的系统中应该设置了自动清理程序&#xff0c;在这个自动清理程序中会对认为没有使用的附件或者图片进行清理。 因为我们更换了存储空间&#xff0c;所以这…

在Linux中使用shell指令完成文件打包、压缩、解压缩

一、写一个1.sh脚本&#xff0c;将以下内容放到脚本中 在家目录下创建目录文件dir在dir下创建dir1和dir2把当前目录下的所有文件拷贝到dir1中&#xff0c;把当前目录下的所有脚本文件拷贝到dir2中把dir2打包并压缩为dir2.tar.xz再把dir2.tar.xz移动到dir1中解压dir1中的压缩包…

triton 客戶端用https协议访问服务

背景 平时调用模型服务&#xff0c;都是用httpIP的链接调用。但由于笔者环境的特殊性&#xff0c;访问模型必须经过一个https的公网URL&#xff0c;所以&#xff0c;如何用triton client访问https链接成为了一个问题 参考 TensorRT&Triton学习笔记(一)&#xff1a;trito…

win7安装python3.8.10遇到的问题及解决办法和相关资源

在我的另一篇文章中&#xff0c;已经测试了win7安装不了python3.10.8 https://blog.csdn.net/kxltsuperr/article/details/132666737 那么&#xff0c;经过搜索&#xff0c;说win7最高可以安装python3.8.10&#xff0c;于是进行安装&#xff0c;结果报错&#xff0c;如下图&a…

【实战】React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(总结展望篇)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

结构型模式-过滤器模式

允许开发人员使用不同的标准来过滤一组对象&#xff0c;通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式&#xff0c;它结合多个标准来获得单一标准。 AllArgsConstructor Data public class Person {private String name;private String gender;p…

【Three.js】第二十一章 Physics 物理

介绍 物理是WebGL可以添加到项目体验中最酷的功能之一。人们喜欢真实物理感的物体&#xff0c;看到它们碰撞、倒塌、坠落和弹跳&#xff0c;就像我的作品集一样&#xff1a; https: //bruno-simon.com/ 有很多方法可以将物理功能添加到您的项目中&#xff0c;这取决于您想要实…

【脑机接口开源数据处理包】brainflowBrainFlow是一个库,旨在获取,解析和分析脑电图,肌电图,心电图和其他类型的数据从生物传感器。

BrainFlow是一个库&#xff0c;旨在获取&#xff0c;解析和分析脑电图&#xff0c;肌电图&#xff0c;心电图和其他类型的数据从生物传感器。 brainflow开源库官网地址 [https://brainflow.readthedocs.io/en/stable/](https://brainflow.readthedocs.io/en/stable/) 它提供了…

我发现了一个很好看的字体,霞鹜文楷!如何换windows和typora字体?

1、字体 官方地址如下&#xff0c;下载也很简单。 https://github.com/lxgw/LxgwWenKai 有1W多的stars。 方式&#xff1a; 直接打包下载。下载不来&#xff0c;可以联系我。 然后ttf的文件&#xff0c;全部安装就行了。 reg save "HKCU\Control Panel" .\res…

C语言入门Day_16 循环的嵌套

目录 前言 1.循环的嵌套 2.循环和判断相互嵌套 3.易错点 4.思维导图 前言 我们已经知道如何通过循环结构来遍历一个一维数组&#xff0c;访问里面的每一个元素。 我们用循环里面的计数器&#xff0c;来作为数组的下标&#xff0c;就可以简单的遍历数组里面的每一个元素。…

知识蒸馏学习

知识蒸馏----教师和学生模型&#xff1a;将已训练完善的模型作为教师模型&#xff0c;通过控制“温度”从模型的输出结果中“蒸馏”出“知识”用于学生模型的训练&#xff0c;并希望轻量级的学生模型能够学到教师模型的“知识”&#xff0c;达到和教师模型相同的表现。 本质上属…

嵌入式开发-11 Linux下GDB调试工具

目录 1 GDB简介 2 GDB基本命令 3 GDB调试程序 1 GDB简介 GDB是GNU开源组织发布的一个强大的Linux下的程序调试工具。 一般来说&#xff0c;GDB主要帮助你完成下面四个方面的功能&#xff1a; 1、启动你的程序&#xff0c;可以按照你的自定义的要求随心所欲的运行程序&#…

从Matrix-ResourceCanary看内存快照生成-ForkAnalyseProcessor(1)

前文看到AutoDumpProcessor的处理逻辑主要是生成&#xff0c;裁剪hprof文件并回调到PluginListener中&#xff0c;接下来我们来看下ForkAnalyseProcessor的处理逻辑。 ForkAnalyseProcessor public class ForkAnalyseProcessor extends BaseLeakProcessor {private static fi…

$nextTick属性使用与介绍

属性介绍 $nextTick 是 Vue.js 中的一个重要方法&#xff0c;之前我们也说过$ref 等一些重要的属性&#xff0c;这次我们说$nextTick&#xff0c;$nextTick用于在 DOM 更新后执行回调函数。它通常用于处理 DOM 更新后的操作&#xff0c;因为 Vue 在更新 DOM 后不会立即触发回调…

【0906 C高级day1】 Linux中的文件相关指令

一、使用cut截取出Ubuntu用户的家目录&#xff0c;要求&#xff1a;不能使用":"作为分割 grep "ubuntu" /etc/passwd | cut -d "/" -n -f 2-3 | cut -c 1-11 二、思维导图 文件相关指令&#xff1a;

【Java Web】Servlet规范讲解

目录 一、前言 二、Servlet规范介绍 2.1 常见版本及新功能 2.2 Servlet的作用 2.3 Servlet的本质 三、Servlet接口和实现类 3.1 Servlet接口 3.2 Servlet接口实现类示例 3.3 Servlet接口实现类开发步骤 3.3.1 关键点 3.3.2 引入Servlet源码包 1、描述 Servlet接口…

LeetCode 725. Split Linked List in Parts【链表】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

【python手写算法】逻辑回归实现分类(含公式推导)

公式推导&#xff1a; 代码实现&#xff1a; # codingutf-8 import matplotlib.pyplot as plt import numpy as npdef f(w1,x1,w2,x2,b):zw1*x1w2*x2breturn 1/(1np.exp(-z)) if __name__ __main__:X1 [12.46, 0.25, 5.22, 11.3, 6.81, 4.59, 0.66, 14.53, 15.49, 14.43,2.1…

优先发展非化石能源

生态兴则文明兴。面对气候变化、环境风险挑战、能源资源约束等日益严峻的全球问题&#xff0c;中国树立人类命运共同体理念&#xff0c;促进经济社会发展全面绿色转型&#xff0c;努力推动本国能源清洁低碳发展。 智慧光伏遮阳伞&#xff0c;搭配座椅设置智能补给休息区&#x…