如何使用 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
我在这里看到一个关于多线程的话题:
所以我照着回答做
我在下面实现了类似的代码,但这里没有任何动静。我知道问题出在我的 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