如何使用 SwingWorker 创建多线程?

How to make multi thread with SwingWorker?

我在这里看到一个关于多线程的话题:

所以我照着回答做

我在下面实现了类似的代码,但这里没有任何动静。我知道问题出在我的 doInBackGround 和流程实施上,但我不知道如何 do.I 是 Swing Builder 的新手,如果这个问题很愚蠢,我深表歉意。该程序只是使面板中的许多圆圈移动。每个圆圈都是由 Swing Worker 创建的线程。

这些是我的 classes:

机器人class:

package com.mycompany.test;

import java.awt.Color;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;

public class Robot extends SwingWorker< Void ,Integer> {
    public int x;
    public int y;
    public Color color;
    public final int speed = 10;
    Robot(int x , int y , Color color)
    {
        this.x = x;
        this.y = y;
        this.color = color;
    }
    public void move_90()
    {
        this.y += speed;
    }

    public void move_270()
    {
        this.y -= speed;
    }

    public void move_180()
    {
        this.x += speed;
    }

    public void move_0()
    {
        this.x += speed;
    }

    public void move_45()
    {
        this.x += speed;
        this.y += speed;
    }

    public void move_135()
    {
        this.x -= speed;
        this.y += speed;
    }

    public void move_225()
    {
        this.x -= speed;
        this.y -= speed;
    }

    public void move_315()
    {
        this.x += speed;
        this.y -= speed;
    }

    public void move()
    {
        Random temp = new Random();
        int rand = temp.nextInt(8);
        switch(rand)
        {
            case 1: move_0();
            break;
            case 2: move_135();
            break;
            case 3: move_180();
            break;
            case 4: move_225();
            break;
            case 5: move_270();
            break;
            case 6: move_315();
            break;
            case 7: move_45();
            break;
            case 8: move_90();
            break;
        }
    }
    @Override
    protected void process(List<Integer> chunks) {
         while(true)
        {
            move();
            if(x < 40) x = 40;
            if(x > PlayField.width - 40) x = (PlayField.width - 40);
            if(y < 40) y = 40;
            if(y > PlayField.height - 40) y = (PlayField.height - 40);
             try {
                 Thread.sleep(20);
             } catch (InterruptedException ex) {
                 Logger.getLogger(Robot.class.getName()).log(Level.SEVERE, null, ex);
             }
        }
    }

    @Override
    protected Void doInBackground() throws Exception {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

机器人模型class:

package com.mycompany.test;

import java.awt.Color;
import java.util.LinkedList;

public class RobotModel {
    public static final int MAX = 8;
    public LinkedList<Robot> model = new LinkedList<Robot>();
    public void add_New_Robot()
    {
        Robot temp = new Robot( 40 , 40 , Color.BLUE);
        model.addFirst(temp);
    }
}

运动场 class :

package com.mycompany.test;

import java.awt.Color;

public class PlayField {
    public static int width;
    public static int height;
    public static Color fill_Color;
    PlayField(int width , int height , Color fill_Color)
    {
        this.width = width;
        this.height = height;
        this.fill_Color = fill_Color;
    }
}

机器人世界class:

package com.mycompany.test;

import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;

public class RobotWorld extends JPanel {
    public RobotModel robot_Model;

    public RobotWorld(RobotModel robot_Model) {
        super();
        this.robot_Model = robot_Model;
        this.setSize(PlayField.width , PlayField.height);
        this.setVisible(true);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D graphic = (Graphics2D)g;
        graphic.setBackground(PlayField.fill_Color);
        for(Robot x : robot_Model.model )
        {
            graphic.setColor(x.color);
            graphic.drawOval(x.x, x.y, 40, 40);
        }
    }

}

最后,GameMain class:

package com.mycompany.test;

import java.awt.Color;
import javax.swing.JFrame;

public class GameMain extends JFrame {
    RobotModel a;
    PlayField field;
    public void Game_Start()
    {
        Robot robot = new Robot(100, 100, Color.RED);
        a = new RobotModel();
        RobotWorld world = new RobotWorld(a);
        world.robot_Model.add_New_Robot();
        this.setSize(field.width , field.height);
        this.add(world);
        this.setVisible(true);
        world.repaint();
    }

//    public void gameUpdate(Robot a , PlayField field)
//    {
//        a.move();
//        if(a.x < 40) a.x = 40;
//        if(a.x > field.width - 40) a.x = (field.width - 40);
//        if(a.y < 40) a.y = 40;
//        if(a.y > field.height - 40) a.y = (field.height - 40);
//    }


    public void gameUpdate(){
    Thread gameThread = new Thread(){
        public void run(){
            while(true){
                //execute one time step for the game
//                gameUpdate(a , field);

                //refresh screen
                repaint();

                //give other threads time
                try{
                    Thread.sleep(5);
                }catch(InterruptedException e){
//                    e.printStackTrace();
                }
            }
        }
    };

    gameThread.start();
}



    public static void main(String args[])
    {
        GameMain main = new GameMain();
        main.Game_Start();
        main.gameUpdate();
    }
}

问题是多方面的,主要是因为不了解 SwingWorker 的实际工作原理。

请记住,更多的线程并不总是意味着更多的工作。您拥有的线程越多,系统就越难工作。有时,少即是多 ;)

SwingWorker 不太适合这个任务。对于整个应用程序,它最多只允许 10 个工作人员执行,除非您正确地将更新与事件调度线程同步,否则您不会从中获得任何好处。

通常更简单的解决方案是改用 Swing Timer。这将确保您的更新在 EDT 内进行,而不会有脏 read/writes 或阻塞 EDT 的风险。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                PlayField playField = new PlayField(200, 200, Color.DARK_GRAY);
                RobotModel model = new RobotModel();
                model.createNewRobot();

                RobotWorld world = new RobotWorld(playField, model);
                world.start();

                frame.add(world);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class RobotModel {

        public static final int MAX = 8;
        public LinkedList<Robot> bots = new LinkedList<Robot>();

        public void createNewRobot() {
            Robot temp = new Robot(40, 40, Color.BLUE);
            bots.addFirst(temp);
        }
    }

    public class PlayField {

        public int width;
        public int height;
        public Color fill_Color;

        PlayField(int width, int height, Color fill_Color) {
            this.width = width;
            this.height = height;
            this.fill_Color = fill_Color;
        }
    }

    public class RobotWorld extends JPanel {

        public RobotModel model;
        private PlayField playField;

        private Timer timer;

        public RobotWorld(PlayField playField, RobotModel robot_Model) {
            super();
            this.model = robot_Model;
            this.playField = playField;

            setBackground(playField.fill_Color);

            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent evt) {
                    Rectangle bounds = new Rectangle(new Point(0, 0), getSize());
                    for (Robot bot : model.bots) {
                        bot.move(bounds);
                    }
                    repaint();
                }
            });
        }

        public void start() {
            timer.start();
        }

        public void stop() {
            timer.stop();
        }

        @Override
        public Dimension getPreferredSize() {
            return playField == null ? super.getPreferredSize() : new Dimension(playField.width, playField.height);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Robot bot : model.bots) {
                Graphics2D graphic = (Graphics2D) g.create();
                bot.paint(graphic);
                graphic.dispose();
            }
        }
    }

    public class Robot {

        public int x;
        public int y;
        public Color color;
        public final int speed = 10;
        public int size = 40;

        Robot(int x, int y, Color color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public void paint(Graphics2D g2d) {
            g2d.setColor(color);
            g2d.fillRect(x, y, size, size);
        }

        public void move_90() {
            this.y += speed;
        }

        public void move_270() {
            this.y -= speed;
        }

        public void move_180() {
            this.x += speed;
        }

        public void move_0() {
            this.x += speed;
        }

        public void move_45() {
            this.x += speed;
            this.y += speed;
        }

        public void move_135() {
            this.x -= speed;
            this.y += speed;
        }

        public void move_225() {
            this.x -= speed;
            this.y -= speed;
        }

        public void move_315() {
            this.x += speed;
            this.y -= speed;
        }

        public void move(Rectangle bounds) {
            Random temp = new Random();
            int rand = temp.nextInt(8);
            switch (rand) {
                case 1:
                    move_0();
                    break;
                case 2:
                    move_135();
                    break;
                case 3:
                    move_180();
                    break;
                case 4:
                    move_225();
                    break;
                case 5:
                    move_270();
                    break;
                case 6:
                    move_315();
                    break;
                case 7:
                    move_45();
                    break;
                case 8:
                    move_90();
                    break;
            }

            if (x < bounds.x) {
                x = bounds.x;
            } else if (x + size > bounds.x + bounds.width) {
                x = bounds.x + bounds.width - size;
            }
            if (y < bounds.y) {
                y = bounds.y;
            } else if (y + size > bounds.y + bounds.height) {
                y = bounds.y + bounds.height - size;
            }
        }

    }
}

有关详细信息,请参阅 How to Use Swing Timers

如果您一心想使用 SwingWorker,那么您应该花时间通读 Worker Threads and SwingWorker