专题导航
一、java调用groovy及groovy中如何使用springBean
二、java运行groovy脚本内存问题及解决
三、java运行groovy脚本并发问题及解决
四、java运行groovy工具类
一、问题重现
之前我们为了解决fullGC问题,使用Map缓存得到的Script对象,达到了类似单例的效果。但是当script运行需要传参时,存在如下问题:高并发下(或极短时间内有两个进程调用同一对象),第一个进程获取到script后,进行参数绑定,但还未执行逻辑代码时,第二个进程又进行参数绑定,则第一个进程则会调用第二个进程的参数
说白了就是:线程不安全
二、解决
线程安全问题,解决起来无非就是:加锁
尝试加锁:
static Lock lock = new ReentrantLock();
public static Object engine(String filePath, String fileName, Map<String, Object> variable) {
Binding binding = new Binding();
if (CollectionUtil.isNotEmpty(variable)) {
variable.entrySet().stream().filter(entry -> StrUtil.isNotBlank(entry.getKey()) && ObjectUtil.isNotEmpty(entry.getValue()))
.forEach(entry -> binding.setVariable(entry.getKey(), entry.getValue()));
}
Object result;
Script script = getScriptInstance(filePath, fileName);
lock.lock();
try {
script.setBinding(binding);
result = script.run();
}finally {
lock.unlock();
}
return result;
}
并发状态下查看运行状态:
线程全部排序运行,多个脚本不存在并发情况
三、继续优化
并发问题解决了,但是多个脚本很明显不存在并发问题,参数也不会修改串联,能否继续优化,让单个对象不能同时被多个线程调用,但不同对象可以并行呢?
话不多说,上代码:
public static Object engine(String filePath, String fileName, Map<String, Object> variable) {
Binding binding = new Binding();
if (CollectionUtil.isNotEmpty(variable)) {
variable.entrySet().stream().filter(entry -> StrUtil.isNotBlank(entry.getKey()) && ObjectUtil.isNotEmpty(entry.getValue()))
.forEach(entry -> binding.setVariable(entry.getKey(), entry.getValue()));
}
Object result;
Script script = getScriptInstance(filePath, fileName);
//对象锁,因为要赋值,所以一个对象同时只能被一个线程调用
synchronized (script){
script.setBinding(binding);
result = script.run();
}
return result;
}
运行结果:
t.run();
}
return result;
}
运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200914164721659.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZlaXFpbmJ1c2hpemhlbmc=,size_16,color_FFFFFF,t_70#pic_center)
可以看到同实例串行,不同实例并行