Вы можете поделиться объектами ScriptEngine
и CompiledScript
по потокам. Они потокобезопасны. Фактически, вы должны делиться ими, поскольку один экземпляр ядра является держателем для кеша класса и скрытых классов объектов JavaScript, поэтому, имея только один, вы сокращаете повторную компиляцию.
Что вы можете ' t является Bindings
объектами. Объект bindings в основном соответствует объекту Global
среды выполнения JavaScript. Двигатель запускается с экземпляром привязки по умолчанию, но если вы используете его в многопоточной среде, вам нужно использовать engine.createBindings()
для получения отдельного объекта Bindings для каждого потока - своего собственного глобального и оценить скомпилированные скрипты в нем. Таким образом вы создадите изолированные глобальные области с тем же кодом. (Конечно, вы также можете объединить их или синхронизировать их, просто убедитесь, что в одном экземпляре привязок не более одного потока). После того, как вы оценили скрипт в привязках, вы можете впоследствии эффективно вызывать функции, определенные им с помощью ((JSObject)bindings.get(fnName).call(this, args...)
. Если вы должны делиться состоянием между потоками, по крайней мере, попробуйте сделать его не изменчивым. Если ваши объекты неизменяемы, вы можете также оценить сценарий в одном экземпляре Bindings
, а затем просто использовать это через потоки (вызывая надежные побочные эффекты). Если он изменен, вам придется синхронизировать; либо целые привязки, либо вы можете использовать специфический JS-API var syncFn = Java.synchronized(fn, lockObj)
Nashorn для получения версий функций JS, которые синхронизируются с определенным объектом.
Это предполагает, что вы используете отдельные привязки по потокам. Если вы хотите, чтобы несколько привязок совместно использовали подмножество объектов (например, путем помещения одного и того же объекта в несколько привязок), снова вам придется как-то справиться с обеспечением того, чтобы доступ к общим объектам был потокобезопасным.
Что касается параметра THREADING
, возвращающего null : да, изначально мы планировали, что не будем делать потоки в потоковом режиме (говоря, что сам язык не является потокобезопасным), поэтому мы выбрали нулевое значение. Возможно, нам придется переоценить это сейчас, так как в то же время мы сделали это так, чтобы экземпляры ядра были потокобезопасными, а глобальная область (привязки) не является (и никогда не будет, из-за семантики языка JavaScript).
Принятый ответ обманет многих людей.
Короче:
NashornScriptEngine
НЕ является потокобезопасным ScriptEngine для Nashorn не является потокобезопасным. Это можно проверить, вызвав ScriptEngineFactory.getParameter («РЕЗЬБА») ScriptEngineFactory для Nashorn.
Возвращаемое значение равно null, которое согласно java doc означает, что он не является безопасным по потоку.
Примечание. Эта часть ответа была впервые задана здесь . Но я сам перепроверял результаты и документ.
Это также дает нам ответ на CompiledScript. Согласно java doc , CompiledScript связан с одним ScriptEngine.
Итак, в Nashorn ScriptEngine и CompiledScript не должны использоваться двумя потоками одновременно.
Образец кода для ответа @ attilla
var renderServer = function renderServer(server_data) {
//your js logic...
return html_string.
}
public static void main(String[] args) {
String jsFilePath = jsFilePath();
String jsonData = jsonData();
try (InputStreamReader isr = new InputStreamReader(new URL(jsFilePath).openStream())) {
NashornScriptEngine engine = (NashornScriptEngine) new ScriptEngineManager().getEngineByName("nashorn");
CompiledScript compiledScript = engine.compile(isr);
Bindings bindings = engine.createBindings();
compiledScript.eval(bindings);
ScriptObjectMirror renderServer = (ScriptObjectMirror) bindings.get("renderServer");
String html = (String) renderServer.call(null, jsonData);
System.out.println(html);
} catch (Exception e) {
e.printStackTrace();
}
}
будьте осторожны при использовании метода renderServer
в многопоточной среде, поскольку привязки не являются потокобезопасными. Одним из решений является использование нескольких экземпляров renderServer
с повторно используемыми пулами объектов. Я использую org.apache.commons.pool2.impl.SoftReferenceObjectPool
, который, кажется, хорошо работает для моего использования.