我正在开发一个可同时打开多个模型的扩展。可以动态打开和关闭模型。模型以LiteWorkspace
的形式打开,以便显示小部件等。每当创建新的LiteWorkspace
时,它都会启动JobThread
和Lifeguard
。问题是关闭GUIWorkspace
(父类LiteWorkspace
)不会杀死其Lifeguard
或JobThread
。
可能的解决方案:
理想的解决方案是让所有模型共享一个JobThread
,因为这将删除线程数量,以限制一个模型可以运行多少个模型。这样做也会带来一定的性能优势。有机会吗?此解决方案仍然需要能够杀死Lifeguard
。
下一步当然是能够杀死线程。
作为最后的选择,我们可以保留GUIWorkspace
个池。当用户关闭模型时,模型将被扔回到池中。然后,当用户加载新模型并且池中有东西时,我们仅重用这些GUIWorkspace
之一。这将允许我们打开与2相同数量的模型。唯一的缺点是,打开新模型(例如,从文件菜单或其他菜单中全新打开)仍然不会杀死线程,因此存在这种永久资源负担闲逛。实际上,出于性能方面的考虑,我们实际上可能必须建立一个池,但是实际上能够在某个时候释放资源将是非常好的。
最佳答案
解决方案1不可行;每个工作区一个JobThread的假设已深深地嵌入到代码中。
要使JobThread消失,这应该足够了:
workspace.jobManager.haltPrimary()
workspace.jobManager.die()
要使GUIWorkspace.Lifeguard线程消失,我们只需要在其上调用
interrupt()
即可,但是即使仅获得对该引用的引用也不是那么容易。这是显示成功尝试的笔录:/Applications/NetLogo 5.0.5 % scala29 -Yrepl-sync -classpath NetLogo.jar
Welcome to Scala version 2.9.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51).
scala> val applet = new org.nlogo.lite.Applet
applet: org.nlogo.lite.Applet = ...
scala> applet.init()
...
scala> val ws = applet.panel.workspace: org.nlogo.window.GUIWorkspace
ws: org.nlogo.window.GUIWorkspace = org.nlogo.lite.LiteWorkspace@69cafecd
scala> import collection.JavaConverters._
import collection.JavaConverters._
scala> Thread.getAllStackTraces().keySet.asScala.foreach(println)
Thread[JobThread,4,main]
Thread[Lifeguard,6,main]
...
scala> ws.jobManager.haltPrimary()
scala> ws.jobManager.die()
scala> import util.Try
import util.Try
scala> for {
thread <- Thread.getAllStackTraces().keySet.asScala
if thread.getName == "Lifeguard"
outer = Try{ val field = thread.getClass.getDeclaredField("this$0")
field.setAccessible(true)
field.get(thread) }
if outer.toOption == Some(ws)
} {
thread.interrupt()
thread.join()
}
Success(org.nlogo.lite.LiteWorkspace@69cafecd)
scala> Thread.getAllStackTraces().keySet.asScala.foreach(println)
...
(请注意,我已经在Scala中回答了;转换为Java留给了读者。用于访问内部类的外部实例的反射内容来自https://stackoverflow.com/a/763617/86485。)
将添加以更简洁的方式添加实现
GUIWorkspace.dispose()
的代码的请求请求。