所以我实际上不确定问题究竟是什么。它可能与我处理我的线程的方式有关,但我不知道如何解决这个问题。
该程序是一个简单的boid模拟,具有不同的“tribed”boid,我想拥有它,以便当我创建一个新的部落时,它在GUI中拥有它自己的面板。现在这在我开始线程之前完美地运行但在此之后它总是冻结。我知道Swing不是线程安全的,但我不知道如何解决这个问题。
以下是添加面板的代码:
val tribeBoxPanels = Buffer.empty[TribeBoxPanel]
val tribeFrames = Buffer.empty[TribeSettingFrame]
val addTribeFrame = ChooseTribeFrame.frame
val addFlockingFrame = AddFlockingFrame.frame
def addTribe(tribe: Tribe) = {
pause()
tribeFrames += new TribeSettingFrame(tribe)
tribeBoxPanels += new TribeBoxPanel(tribe)
refcontents
}
private def refcontents = {
top.optionPanel.contents.clear()
top.optionPanel.contents += new BoxPanel(Orientation.Vertical) {
tribeBoxPanels.foreach(contents += _.tribeBoxPanel)
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.addTribeButton
}
top.optionPanel.contents += new BoxPanel(Orientation.Horizontal) {
contents += top.vectorDebugButton
}
pause()
}
接下来是(runnable)线程的代码:
private var running = true
def pause() = {
if (running) {
running = false
t.stop()
}
else {
running = true
t = new Thread(BoidSimulation)
t.start()
}
}
var t = new Thread(BoidSimulation)
t.start()
我试图在添加部落时停止线程,但这似乎不起作用,GUI仍然冻结。我也尝试过t.interrupt()(因为这是更好的方法),但这也不起作用。
编辑:我的问题可能是我试图从另一个非GUI2D的对象(该方法所在的对象)调用方法AddTribe。也许如果我将所有代码粘贴到GUI2D类,它会起作用吗?
编辑2:尝试调用这样的方法:
def invoke(tribe: Tribe) = new Runnable() { def run() = addTribe(tribe) }
没有帮助,但我试图添加东西仍然冻结。
我也尝试打印出调用方法的线程,这就是我得到的:
Thread[Thread-2,5,main] <- println(t)
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- This call works
Thread[AWT-EventQueue-0,6,main] <- After this it freezes.
因此该方法是从AWT线程调用的,但它仍然冻结了GUI。那么线程不是我的问题吗?
编辑3:我想我发现了我的问题!!实际上它倒退了。因为按下按钮调用该方法,Swing正在尝试完成计算线程的代码,这就是导致它冻结的原因。现在我需要找出SwingUtilities.invokelater()
的精确对立面编辑4:尝试创建一个可以运行该代码的新runnable,但它仍然以某种方式从AWT线程调用。这是什么原因以及如何从计算线程中运行代码?
class AddTribe(dist: Int, maxSpeed: Int, boidMass: Int, color: Color, behavior: Behavior, boidAmount: Int) extends Runnable {
println(Thread.currentThread())
def run() = BoidSimulation.addTribe(dist: Int, maxSpeed: Int, boidMass: Int, color: Color, behavior: Behavior, boidAmount: Int)
}
case ButtonClicked(e) if (e == addButton) => {
new AddTribe(distSlider.value, maxSpdSlider.value / 10, massSlider.value / 10, color, new Flocking(separationSlider.value, alignmentSlider.value, cohesionSlider.value), boidSlider.value).run()
答案 0 :(得分:3)
关于Swing线程要记住的关键是:
SwingUtilities.invokeLater()
将工作添加到Swing线程的队列中,或使用SwingWorker
帮助程序类。另请参阅有关这些主题的Java教程:
<强>更新强>
您可以通过添加调试语句来检查运行任何给定位代码的线程,例如:
println(Thread.currentThread)
或使用调试工具。它有助于使用appropriate constructor为您自己创建的任何线程提供可读的名称。
答案 1 :(得分:0)
直接在telnet <yourservername> smtp
HELO <yourservername and then enter>
MAIL from: <mailaddr and then enter>
RCPT to: <mailaddr and then enter>
DATA
354 End data with <CR><LF>.<CR><LF>
From: <mailaddr and then enter>
To: <mailaddr and then enter>
Subject: test
This is test
.
250 2.0.0 Ok: queued as 4C67244003
QUIT <and then enter>
221 2.0.0 Bye
Connection closed by foreign host.
上调用.run()
将在当前线程上运行它。单独运行它的最简单方法是创建一个新的Runnable
和Thread
:
start()
每次按下按钮时启动一个新线程虽然效率不高;您可能更愿意例如使用case ButtonClicked(e) if (e == addButton) =>
new Thread(new AddTribeRunnable(...)).start()
来管理线程池。或者,对于更先进/更高性能的技术,您可以使用akka Actors。