2011-08-16 103 views
2

我使用Play!大量使用javax.script包(包括ScriptEngine)的框架。由于ScriptEngines的创建成本很高,因此可以跨多个请求使用它们(我不打算创建多个ScriptEngines,每个线程一个 - 至少我不会为每个请求反复创建ScriptEngines)。玩!框架:通过多个请求重复使用实例

我认为这种情况不限于ScriptEngines,框架中可能有些东西我不知道要处理这种情况。

谢谢你的任何想法,你有! Malax

+0

有一个单一的静态实例不足吗? Play框架是JEE组件模型的反论点,因为它在请求之间很大程度上保持无状态。 – Jeremy

+0

这是我的第一枪,拥有一个脚本引擎的静态实例。问题在于,ScriptEngines不是线程保存,并且由于线程池调度请求(并且线程间共享静态字段),引擎可能会被不同的线程并发使用。关于静态实例的 – Malax

回答

2

播放是无状态的,所以没有“会话式”机制将对象链接到用户。您可能有两种选择:

使用缓存。将ScriptEngine存储在具有唯一ID的缓存中,并添加一个方法来检查它是否仍然存在。喜欢的东西:

public static Engine getScriptEngine(Long userId) { 
    String key = "MY_ENGINE" + userId; 
    ScriptEngine eng = (ScriptEngine) Cache.get(key); 
    if(eng == null) { 
     eng = ScriptEngine.create(); 
     Cache.put(key, eng); 
    } 
    return eng; 
} 

或者创建一个包含的ScriptEngine的静态实例所以它总是在那里,一旦服务器启动一个单独的对象。

我会说缓存一是最好的办法。

编辑:您的评论,这将取决于情况:

  1. 如果你想重用跨独特用户的多个请求(即每个用户都有自己的ScriptEngine一起工作),一个引擎缓存方法在缓存将引擎链接到用户标识时起作用。这也可以解决任何线程问题。
  2. 否则,如果您想跨多个用户的多个请求重用它,静态方法是一种更好的方法。但正如你所说的,在Play或任何系统中访问都不是线程安全的。

我在想你最好的选择是与他们异步工作。我不知道你将如何使用ScriptEngines,但尝试做这样的事情:

  • 根据要求,存储从数据库的表中的条目标识的ScriptEngine处理请求
  • 在相同的请求,启动asynchronous作业(或每30秒运行一次)
  • 作业将读取表格的第一个条目,将其删除,执行任务并将答案返回给用户。这个工作可能有一个ScriptEngine池可以使用。
  • 由于当前工作正在进行时,作业不会再次启动,如果您有足够的请求,作业将永不停止。如果这样做,这意味着您当时不需要引擎,并且会根据需要重新创建它们。

这样你就可以线性工作,忽略线程问题。如果你不能做到这一点,那么你需要修复ScriptEngine的线程安全性,因为你不能假装共享一个对象,它不会在线程安全的环境中产生多线程的服务器环境:)

+0

- 请参阅我对主要问题的评论。缓存解决方案似乎也出现了这个问题。 :( – Malax

+0

+1使用游泳池。 – Jeremy

0

为什么不实施脚本池?因此,每个请求都以与JDBC连接池相同的方式从池中获取实例。 但请确保脚本引擎是无状态的。