BeanShell:多线程环境下Interpreter解释器的优化使用

BeanShell是用 Java 编写的一个小型、免费、可嵌入的 Java 代码的脚本解释器。 BeanShell动态执行标准Java语法,并使用通用语法对其进行扩展 脚本编写便利性,适用于 Java 的轻量级脚本。本文说明在并发环境下对BeanShell更加优化的使用方式。

简单示例

如下是一个简单的使用BeanShell脚本解释执行脚本的示例:

	@Testpublic void testBsh() {try {/** 创建脚本解释器实例 */Interpreter interpreter = new Interpreter();  /** 定义脚本中引用的内置变量 */interpreter.set("name", "world");/** 执行脚本,脚本中访问内置对象的字段,保存运行结果到res */Object res = interpreter.eval("\"hello \"+ name");/** 输出hello world */System.out.println("res "+res);assertTrue("hello world".equals(res));} catch (EvalError e) {e.printStackTrace();assertFalse(true);}}

BeanShell官方的示例差不多都是这样的,看起来非常简单。

线程安全

在实际工程也可以如上使用,在我的项目中,我差不多也是这么用的。
但每次都创建一个Interpreter实例,这样真的有必要么?初步看了bsh.Interpreter的源码,其构造方法在构造实例时的逻辑还是有些复杂的。所以如果频繁的创建/销毁Interpreter实例其实是有不小的系统开销的。Interpreter实例可不可以在并发环境下由多线程复用呢?如果可以就只需要创建一个静态实例就可以了,岂不是更有效率?
所以,Interpreter实例是线程安全的(thread-safe)的么?如果是,那么上面的想法就是现实的。
带着这个问题我翻阅了BeanShell的官方文档,得到的答案是肯定的。

BeanShell is thread-safe internally, so as long as your scripts do not explicitly do anything ordinarily non-thread safe (e.g. access shared variables or objects) you can write multi-threaded scripts.

BeanShell 在内部是线程安全的,所以只要你的脚本不显式执行任何通常非线程安全的操作(例如访问共享)变量或对象),您可以编写多线程脚本。

摘自《Threads - Scripting Runnable》 https://beanshell.github.io/manual/interfaces.html#Threads_-_Scripting_Runnable

NameSpace(名字空间)

虽然bsh.Interpreter可以在并发环境下使用,但就上面示例而言并不是简单的将 interpreter定义成静态成员变就可以安全的让多线程共享interpreter实例的。
因为interpreter.set("name", "world");这行语句实际是在interpreter的全局名字空间(bsh.NameSpace)定义变量(即Interpreter.globalNameSpace成员),这实际上是在修改interpreter实例的成员状态,在并发环境下,多个线程如果都这样执行,就会互相干扰,无法得到正确的结果。

eval

如下是 bsh.Interpreter.eval(Reader,NameSpace,String)方法的实例代码片段
在这里插入图片描述
可以看到在调用eval方法执行脚本的时候,eval又创建一个内部的解释器实例,所以它可以保证线程安全。
只是在创建这个内部实例的时候,把当前实例做为父实例参数传递给了构造方法。这个新的实例即可以访问父实例的名字空间也可以有自己单独使用的名字空间。

优化方案

看懂了eval执行脚本的逻辑,在上面示例的基础上可以如下修改,即减少无谓的实例创建和销毁,又可以保证在并发环境下的线程安全。
请注意下面示例中执行脚本调用的是Interpreter.eval(String,NameSpace)方法而不是上面示例中的Interpreter.eval(String)方法

public class BshTest{/** 创建脚本解释器实例静态成员 */private static final Interpreter interpreter = new Interpreter();  @Testpublic void testBsh() {try {/** * 多线程环境下为了确保不同线程间命名空间互相不干扰,创建临时名字空间对象* 用于定义脚本中引用的变量*/NameSpace ns = new NameSpace(interpreter.getNameSpace(), "test");/** 在临时命名空间对象中定义脚本中引用的内置变量 */ns.setVariable("name", "world", false);/** * 调用 Interpreter.eval(String,NameSpace)方法执行脚本* 将临时名字空间对象传递给解释器*/Object res = interpreter.eval("\"hello \"+ name",ns);/** 输出hello world */System.out.println("res "+res);assertTrue("hello world".equals(res));} catch (EvalError e) {e.printStackTrace();assertFalse(true);}}

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

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

相关文章

零信任:基于Apisix构建认证网关

背景 零信任一直是我们未来主攻的一个方向,全球加速,SD-WAN组网都是一些非常成熟的产品,全球加速是我们所有产品的底座,SD-WAN解决的是多个网络打通的问题,而零信任则主打应用访问。 关于零信任,我们已经…

oracle服务器的CPU占用率一直100%排查方式

背景说明 公司开发、测试、演示环境,三个环境的oracle服务器无论服务器是否空闲, CPU的占用率一直是100%, 一直也没有找到问题原因,今天就花了一整天时间研究这个问题。 通过AWR报告查看oracle运行情况 awr报告是oracle 10g下提…

基于Docker环境下的Jenkins搭建及使用

目录 前言: Docker下安装Jenkins 启动Jenkins Jenkins插件下载 配置Jenkins 修改Jenkins时间 配置Python3环境 配置HTML报告/Allure报告 Allure报告配置 简单使用-实例构建 参数化构建 构建后操作 配置成功 控制台输出 Allure报告查看 HTML报告查看 前言&#xff1a…

mac m1通过qemu和grub制作操作系统引导盘

文章目录 前言grub安装引导盘FAQ参考附录qemu安装ubuntuGRUB安装到回环设备吧啦吧啦... 前言 我电脑是mac m1芯片的,做了如下尝试,最终在第4种方式下成功: 开始用了parallels desktop安装了ubuntu 22版本的,因为本机是arm64芯片…

vue js实现表格行拖拽

效果图&#xff1a; <a-table :dataSource"dataSource" :columns"columns" :pagination"false"><template #bodyCell"{ column, record }"><template v-if"column.key td"><div style"cursor: p…

【容器起不来~tomcat】

记录一次线上容器~tomcat起不来的场景: **部门由于资金有限,只能用tomcat去部署,话不多说直接贴图: Docker 镜像 Tomcat 启动失败– 查看线上日志,日志报错了,报错内容如下: 1,Error response from daemon: driver failed programming external connectivityon endpoint jen…

R 语言 ggplot2 PCA 主成分分析(虚拟数据集)

生成虚拟数据集 library(ggplot2)data.matrix <- matrix(nrow 100, ncol 10)colnames(data.matrix) <- c(paste("wt",1:5,sep ""),paste("ko",1:5,sep "") )rownames(data.matrix) <- paste("gene",1:100,sep…

Modin 入门学习

Modin 是一个 Python 第三方库&#xff0c;用于加速 Pandas 的 API 执行速度。原始的 Pandas 是单线程执行的&#xff0c;而 Modin 则重新打包了 Pandas 里面的 API&#xff0c;使其同时在多个内核中运行&#xff0c;提高硬件性能的利用率。 使用方法很简单&#xff0c;安装 M…

车载软件架构 —— 闲聊几句AUTOSAR OS(七)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕的就是把别人的眼光当成自己生活的唯一标…

CAD Voronoi 3D三维泰森多边形维诺图插件三维狄利克雷镶嵌(Dirichlet tessellation)

三维Voronoi Voronoi又名泰森多边形或Dirichlet图、维诺图等&#xff0c;三维Voronoi是由连接两邻点直线的垂直平分面组成的连续三维多面体结构。Voronoi在各个学科中应用广泛&#xff0c;如进行区域规划、晶体塑性有限元研究、路径优化、地形简化、多孔结构力学等方面的分析。…

蓝桥杯专题-试题版-【危险系数】【网络寻路】【高僧斗法】【约数倍数选卡片】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

Apollo分布式配置中心(二)

上一篇&#xff1a; 上一篇已经知道Apollo是什么东西了&#xff0c;接下来实践一下 目录 一、创建应用 1、 新增配置 2、创建Namespace ​3、同步配置 4、灰度发布 添加灰度配置项 ​编辑 配置灰度规则 二、删除应用、集群、appNamespace 三、springBoot整合Apollo …