【问题标题】:Nashorn MultiThread ProgrammingNashorn 多线程编程
【发布时间】:2016-03-15 12:56:15
【问题描述】:

如果以下代码可以在多线程应用程序中工作,您能帮我看看吗?

这是我的 Java 脚本,将由 Nashorn 评估

var Thread = Java.type("java.lang.Thread");
var referenceNumberValid = "0000";
var referenceNumberInvalid = "0001";

function validate (parameters) {
    var isValid = false;
    var statusCode;
    var referenceNumber = parameters.referenceNumber;
    var validateNumber = referenceNumber.substr(0, 7);
    var sum = 0;

    for (ctr = 0; ctr < validateNumber.length; ctr++) {
        sum += parseInt(validateNumber.substr(ctr, 1));
    }

    var checkDigit = sum % 10;
    isValid = parseInt(referenceNumber.substr(7, 1)) == checkDigit;
    statusCode = isValid ? referenceNumberValid : referenceNumberInvalid;

    print("Thread: " + Thread.currentThread().getId() + ", isValid: " + isValid + ", referenceNumber: " + referenceNumber + ", validateNumber: " + validateNumber + ", sum: " + sum + ", checkDigit: " + checkDigit + ", statusCode" + statusCode);

    return statusCode;
}

这就是我创建脚本引擎的方式

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(myScript);

虽然使用 Testng 进行测试,但没有任何错误

@Test(dataProvider = "validReferenceNumbers", timeOut = 3000)
public final void testValidReferenceNumber(String referenceNumber) throws NoSuchMethodException, ScriptException {
    Map<String, String> parameters = new HashMap<>();
    parameters.put("referenceNumber", referenceNumber);   
    Invocable invocable = (Invocable) engine;
    Object result = invocable.invokeFunction("validate", parameters);       
    Assert.assertEquals(statusCode, "000");
}

@DataProvider(name = "validReferenceNumbers")
private Iterator<Object[]> validReferenceNumbers() throws FileNotFoundException {
    Iterator<Object[]> testData = null;  
    // please assume that will be initilized correctly 
    return testData;
}

测试结果1 - 注意有些数据是重复的

Thread: 10, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 11, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 12, isValid: true, referenceNumber: 17028884, validateNumber: 1702888, sum: 34, checkDigit: 4, statusCode0000
Thread: 13, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 14, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 15, isValid: true, referenceNumber: 17098881, validateNumber: 1709888, sum: 41, checkDigit: 1, statusCode0000
Thread: 16, isValid: true, referenceNumber: 17098881, validateNumber: 1709888, sum: 41, checkDigit: 1, statusCode0000
Thread: 17, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 18, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 19, isValid: true, referenceNumber: 17058887, validateNumber: 1705888, sum: 37, checkDigit: 7, statusCode0000
Thread: 20, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 21, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 22, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 23, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 24, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 25, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 26, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 27, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 28, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 29, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 30, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 31, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 32, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 33, isValid: true, referenceNumber: 17058887, validateNumber: 1705888, sum: 37, checkDigit: 7, statusCode0000
Thread: 34, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 35, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 36, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 37, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 38, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 39, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 40, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 41, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 42, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 43, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 44, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 45, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 46, isValid: true, referenceNumber: 07034880, validateNumber: 0703488, sum: 30, checkDigit: 0, statusCode0000
Thread: 47, isValid: true, referenceNumber: 07034880, validateNumber: 0703488, sum: 30, checkDigit: 0, statusCode0000
Thread: 48, isValid: true, referenceNumber: 07009882, validateNumber: 0700988, sum: 32, checkDigit: 2, statusCode0000

但如果我将“parallel=true”添加到 @DataProvider 我的脚本开始失败

@Test(dataProvider = "validReferenceNumbers", timeOut = 3000)
public final void testValidReferenceNumber(String referenceNumber) throws NoSuchMethodException, ScriptException {
    Map<String, String> parameters = new HashMap<>();
    parameters.put("referenceNumber", referenceNumber);   
    Invocable invocable = (Invocable) engine;
    Object result = invocable.invokeFunction("validate", parameters);       
    Assert.assertEquals(statusCode, "000");
}

@DataProvider(name = "validReferenceNumbers", parallel=true)
private Iterator<Object[]> validReferenceNumbers() throws FileNotFoundException {
    Iterator<Object[]> testData = null;  
    // please assume that will be initilized correctly 
    return testData;
}

测试结果2 - 请注意,重复某些数据以表明相同的参考编号在测试期间可能会随机失败

Thread: 29, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 22, isValid: false, referenceNumber: 18058888, validateNumber: 1805888, sum: 1, checkDigit: 1, statusCode0001
Thread: 25, isValid: false, referenceNumber: 18058888, validateNumber: 1805888, sum: 1, checkDigit: 1, statusCode0001
Thread: 21, isValid: true, referenceNumber: 17098881, validateNumber: 1709888, sum: 41, checkDigit: 1, statusCode0000
Thread: 27, isValid: false, referenceNumber: 18028885, validateNumber: 1802888, sum: 1, checkDigit: 1, statusCode0001
Thread: 20, isValid: true, referenceNumber: 17098881, validateNumber: 1709888, sum: 41, checkDigit: 1, statusCode0000
Thread: 26, isValid: true, referenceNumber: 17058887, validateNumber: 1705888, sum: 37, checkDigit: 7, statusCode0000
Thread: 24, isValid: true, referenceNumber: 17028884, validateNumber: 1702888, sum: 34, checkDigit: 4, statusCode0000
Thread: 23, isValid: false, referenceNumber: 18028885, validateNumber: 1802888, sum: 1, checkDigit: 1, statusCode0001
Thread: 28, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 30, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 32, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 34, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 31, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 36, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 38, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 40, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 42, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 44, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 33, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 46, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 48, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 35, isValid: false, referenceNumber: 18058888, validateNumber: 1805888, sum: 30, checkDigit: 0, statusCode0001
Thread: 50, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 37, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 39, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 41, isValid: true, referenceNumber: 17058887, validateNumber: 1705888, sum: 37, checkDigit: 7, statusCode0000
Thread: 52, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 54, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 43, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 45, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 56, isValid: true, referenceNumber: 07009882, validateNumber: 0700988, sum: 32, checkDigit: 2, statusCode0000
Thread: 58, isValid: true, referenceNumber: 07034880, validateNumber: 0703488, sum: 30, checkDigit: 0, statusCode0000
Thread: 47, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 49, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 51, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 53, isValid: true, referenceNumber: 18028885, validateNumber: 1802888, sum: 35, checkDigit: 5, statusCode0000
Thread: 55, isValid: true, referenceNumber: 18058888, validateNumber: 1805888, sum: 38, checkDigit: 8, statusCode0000
Thread: 57, isValid: true, referenceNumber: 07034880, validateNumber: 0703488, sum: 30, checkDigit: 0, statusCode0000

谁能确认我是否可以初始化 ScriptEngine 并允许它在多线程应用程序中使用。如您所见,我使用全局脚本变量,但在执行期间不会修改这些变量。由于我们的设计围绕着一个在内部调用此脚本的 Web 服务。

P.S.据我了解,@DataProvider(parallel=true) 是测试多线程的正确方法,所以如果我错了,请指出。

编辑谁能告诉我如何修改我的代码/脚本,以便我可以初始化 ScriptEngine 并允许它在 多线程 应用。因为我不想一遍又一遍地解析脚本文件。

正如我之前认为的,如果脚本不使用全局 保持状态的变量就可以了,但显然不是 够了。

谢谢

【问题讨论】:

  • Nashorn 是 not thread-safe。你问的是这个吗?
  • 您好,感谢您的评论。实际上,我要问的是正确的方法是什么,以便我可以编译我的脚本并将其用作多线程应用程序(如果可能的话)。正如我之前认为的那样,如果我将所有数据操作都放在函数中并且不使用全局变量来保持状态就足够了。

标签: javascript java multithreading testng nashorn


【解决方案1】:

您可以初始化ScriptEngine 并在多线程应用程序中使用它。

您需要创建一个 CompiledScript 实例,而不是 engine.eval(myScript);,以便稍后将其评估为 Bindings 实例:

Compilable compilable = (Compilable) engine;
CompiledScript script = compilable.compile(myScript);

而不是使用你的engine 作为Invocable,你需要为每个线程/测试创建一个Bindings 实例,将编译后的脚本评估到其中,获取包装函数的script object mirror,然后call函数:

@Test(dataProvider = "validReferenceNumbers", timeOut = 3000)
public final void testValidReferenceNumber(String referenceNumber) throws ScriptException {
    Map<String, String> parameters = new HashMap<>();
    parameters.put("referenceNumber", referenceNumber);
    Bindings bindings = engine.createBindings();
    script.eval(bindings);
    ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) bindings.get("validate");
    Object result = scriptObjectMirror.call(null, parameters);
    /* insert result assertions here */
}

来源:

【讨论】:

  • 嗨,感谢您的回答,这对我有用。但是,只有一个后续问题。 “scriptObjectMirror.call(this, parameters)”中的“this”参数有什么作用
  • @JefreyValencia,好问题。经过进一步调查,它看起来像是 JavaScript 中的 func.apply(thiz, args) 中的 thiz(参见 Function.prototype.apply() - JavaScript | MDN)。我已更新代码示例以改用 null。谢谢!
  • @mfulton26,再次感谢
  • 另一方面,调用 CompiledScript.eval(Binding b) 会将更改应用于作为其包含的 ScriptEngine 一部分的绑定,而不是您作为参数传递的绑定。那里有很大的不同。
  • 我尝试这样做并将 ScriptObjectMIrror 对象存储在 ThreadLocal 对象中,但它似乎不是线程安全的。这可能与上面提到的@NishM 有关。有没有人真正让它在多个线程中运行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-03-10
  • 2010-11-25
  • 2014-09-11
相关资源
最近更新 更多