Как запретить ScriptEngine (Nashorn) eval () от блокировки потоков [дублировать]

41
задан And390 9 May 2015 в 12:47
поделиться

4 ответа

Вы можете поделиться объектами 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).

50
ответ дан Alexey Subach 25 August 2018 в 14:17
поделиться

Принятый ответ обманет многих людей.

Короче:

  • NashornScriptEngine НЕ является потокобезопасным
  • Если вы НЕ используя глобальные привязки, часть без учета состояния может быть потокобезопасной
0
ответ дан Beloo 25 August 2018 в 14:17
поделиться

ScriptEngine для Nashorn не является потокобезопасным. Это можно проверить, вызвав ScriptEngineFactory.getParameter («РЕЗЬБА») ScriptEngineFactory для Nashorn.

Возвращаемое значение равно null, которое согласно java doc означает, что он не является безопасным по потоку.

Примечание. Эта часть ответа была впервые задана здесь . Но я сам перепроверял результаты и документ.

Это также дает нам ответ на CompiledScript. Согласно java doc , CompiledScript связан с одним ScriptEngine.

Итак, в Nashorn ScriptEngine и CompiledScript не должны использоваться двумя потоками одновременно.

5
ответ дан Community 25 August 2018 в 14:17
поделиться

Образец кода для ответа @ attilla

  1. my js-код выглядит примерно так:
    
    var renderServer = function renderServer(server_data) {
       //your js logic...
       return html_string.
    }
    
  2. код java:
    
    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, который, кажется, хорошо работает для моего использования.

0
ответ дан mt.uulu 25 August 2018 в 14:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: