如何处理变慢的SwingWorker线程?

时间:2019-03-30 16:27:06

标签: java multithreading swing swingworker

我很难理解多线程技术。开始研究它时,我想到了一个问题。我最近写了一个简单的应用程序,一旦我获得了有关Java的一些新知识,就希望以我所学的知识来改进我的应用程序。 看起来像简单的摆动GUI,它每隔一段时间就会更新一次图像。我实现了 ActionListener ,并覆盖了 actionPerformed 方法。延迟15毫秒的计时器,重新粉刷了 JPanel 类,一切正常。但是我认为直接在actionPerformed中使用计时器更新GUI(我想这是另一个线程,但我不太确定)是个坏主意。因此,我决定更改代码并使用SwingWorker。我在 process() ..内部调用了我动画的所有方法,然后应用程序再次正常运行,但是速度变得非常慢。 现在我在想怎么了?为什么它的动作比以前慢?我的计时器延迟实际上没有等待15ms,即使延迟相同也要慢得多。我在多线程方面犯了错误吗? 帮我了解这些东西。预先感谢

public class GameEngine() extends SwingWorker<Void, Drawable>
GamePanel gp; // ref to JPanel class
{
 public GameEngine(GamePanel gp)
 {
  this.gp = gp;
 }
}
protected void doInBackground()
{
 publish();
}
protected void process(List<Drawable> chunks)
{
 Timer timer = new Timer(15, e ->
 {
  //methods for animation 
  fall();
  animate();
  checkTouch();
 });
}

我遗漏了一些代码。如果您需要我可以写...

EDITION

为清楚起见,我提供了更多示例和补充说明。

**以前是:**

public class GamePanel extends JPanel
{
 public void GamePanel()
 {
 GameEngine engine = new GameEngine(this);
 }
 //some images , variables etc...
  protected void paintComponent(Graphics g)
  super.paintComponent(g)
  g.drawImage(image1, x, y, null);
  g.drawImage(image2, w, z,null);
 ...
}
public class GameEngine () implements ActionListener
{
 GamePanel gp;
 Timer timer;
 public void GameEngine(GamePanel gp)
 {
  this.gp = gp;
  timer = new Timer( 15 , this );
 }
 public void actionPerformed()
 {
  //these methods repaint my GamePanel every 15ms.
  fall(); // make object (image) increment on Y Axis 
  animate(); // make another object (image) decrement on X Axis
  checkTouch(); // check if objects collided
 }
}

**蜜月:**

public class GamePanel extends JPanel
{
 public void GamePanel()
 {
 GameEngine engine = new GameEngine(this);
 }
 //some images , variables etc...
  protected void paintComponent(Graphics g)
  super.paintComponent(g)
  g.drawImage(image1, x, y, null);
  g.drawImage(image2, w, z,null);
 ...
}
public class GameEngine () extends SwingWorker<Void, Drawable>
{
 GamePanel gp;
 Timer timer;
 public void GameEngine(GamePanel gp)
 {
  this.gp = gp;
 }
 protected void doInBackground()
 {
  process();
 }
 protected void progress()
 {
  timer = new Timer (15, e-> 
  {
   new ActionListener(new actionPerformed)
   {
      //these methods repaint my GamePanel every 15ms.
  fall(); // make object (image) increment on Y Axis 
  animate(); // make another object (image) decrement on X Axis
  checkTouch(); // check if objects collided
   }
  });
 }
 protected void done()
 {
 };
}

当我第一次创建它时,我实现了ActionListener并通过构造函数中声明的计时器更新了我的面板。我认为它是线程不安全的。 这就是为什么我将所有进行中的方法都转移到其中将Timer声明为ActionListener的Lambda参数的原因。 换句话说,我在另一个线程中调用了所有动画方法。 最终,与第一个示例相比,它变慢了。 我不明白

  1. 是第一个示例EDT中的Timer还是另一个线程?
  2. 我的第一个示例是线程安全的?
  3. 为什么我的第二个例子比第一个例子慢得多?

我听说过不在EDT之外更新您的GUI,是这种情况吗?

1 个答案:

答案 0 :(得分:2)

您的问题中没有足够的信息来回答,但我将带您处理有关多线程的问题以及有关Swing和渲染的隐含问题,以查看是否可以为您提供帮助。

我认为最慢的原因是不必要的屏幕更新。一旦在画布上或应用程序中的任何内容上绘制了一个像素,通常您的应用程序不需要重绘它,除非应该更改它;精灵移动或应用中的其他图像暂时遮住了图形的一部分,然后需要还原。

新手重涂通常会忽略这一点,而只重涂整个已涂漆的表面。虽然可以,但是很慢。如果您要在一个循环中进行多次,那么该循环似乎会很慢。

执行此操作的更好方法是使用传递到重绘例程中的矩形,并仅重绘其与例程重绘的整个曲面的交点-这样可以减少需要重绘的部分,因此重绘所需的时间。

对于多线程,我认为以我们以前在单处理器世界中思考事物的方式来思考它是有帮助的-计算机会做一段时间,然后停在您无法预测的位置并做某事在另一线程中等待一会儿,等等。您无法假设事情的完成顺序,或花费在每件事上的时间等。

使用现代的多核计算机,实际上有可能同时完成这些事情,但是我不知道尝试设想对您有帮助。