Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is an evaluated function in Nashorn reusable from different threads?

Is it possible to reuse one and the same Nashorn engine and one and the same JavaScriptObject, which results as the evaluation of a JS-function, for all servlet requests, if the function does not change any shared object but uses only the arguments given with the call? Look at the following example:

public class MyServlet extends HttpServlet {

private ScriptEngineManager factory;
private ScriptEngine engine;
private ScriptObjectMirror script;

@Override
public void init() throws ServletException {
    try {
        factory = new ScriptEngineManager();
        engine = factory.getEngineByName("nashorn");
        script = (ScriptObjectMirror)engine.eval("function(writer) {writer.print('Hello, World!');}");
    } catch (ScriptException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        script.call(null, writer);
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Is this thread-safe? This is a follow-up to Reuse Nashorn ScriptEngine in Servlet

Edit: I'm not sure what difference this makes for the question at hand, but to focus on the more interesting question, under which circumstances a call to an evaluated js-function is thread save, I made all fields final now. So the code is:

public class MyServlet extends HttpServlet {

final private ScriptEngineManager factory;
final private ScriptEngine engine;
final private ScriptObjectMirror script;

public MyServlet() {
    factory = new ScriptEngineManager();
    engine = factory.getEngineByName("nashorn");
    ScriptObjectMirror _script = null;
    try {
        _script = (ScriptObjectMirror) engine.eval("function(writer) {writer.print('Hello, World!');}");
    } catch (ScriptException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
    script = _script;
}

@Override
public void init() throws ServletException {
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
    try (PrintWriter writer = res.getWriter()) {
        script.call(null, writer);
        writer.close();
    } catch (IOException ex) {
        Logger.getLogger(MyServlet.class.getName()).log(Level.SEVERE, null, ex);
    }
}
like image 909
Gregor Avatar asked Nov 10 '22 21:11

Gregor


1 Answers

None of your instance variables are safely published, so that's a big "no" right there. Also none of the documentation says that the classes you use are thread safe, so without some further documentation saying differently you have to assume that they are not thread safe.

Answer: nope.

like image 82
markspace Avatar answered Nov 14 '22 22:11

markspace