停止线程以及在哪里使用锁

时间:2014-04-04 22:34:02

标签: java multithreading

我的问题是在这些线程上使用锁的位置。当我让我的圈子相互竞争时,当一个人到达终点时,程序应该停止并宣布获胜者。相反,它完成了所有圆圈到终点线,我相信这是因为他们都共享相同的锁,甚至可能是资源。

以下是我的三个班级。任何帮助将不胜感激。

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import java.awt.GridLayout;

public class HorsePanel extends JFrame {

private JPanel panel;
private JButton reset;
private JButton quit;
private JButton run;
private ActionListener listener;
public static final int FRAME_WIDTH = 500;
public static final int FRAME_HEIGHT = 400;

private TrackPane trackPane;

public HorsePanel(TrackPane t) {
    trackPane = t;
    createPanel();
    createRunRace();
    createQuit();
    setSize(FRAME_WIDTH, FRAME_HEIGHT);
}

public void createRunRace() {

    class RunRace implements ActionListener {

        public void actionPerformed(ActionEvent rightEvent) {
            run.setEnabled(false);
            trackPane.start();

        }
    }

    ActionListener a = new RunRace();
    this.run.addActionListener(a);
}

public void createQuit() {
    class QuitRace implements ActionListener {

        public void actionPerformed(ActionEvent rightEvent) {
            System.exit(0);
        }
    }

    ActionListener b = new QuitRace();
    this.quit.addActionListener(b);
}


public void createReset() {
    class ResetRace implements ActionListener {

        public void actionPerformed(ActionEvent rightEvent) {
            //trackPane.resetCoordinates;
            run.setEnabled(true);
        }
    }

    ActionListener c = new ResetRace();
    this.reset.addActionListener(c);
}

public void createPanel() {
    panel = new JPanel(new BorderLayout());
    trackPane = new TrackPane();
    this.run = new JButton("Run Race");
    this.quit = new JButton("Quit");
    this.reset = new JButton("Reset");
    JPanel topPanel = new JPanel();

    topPanel.setLayout(new GridLayout(1, 3));
    topPanel.add(run);
    topPanel.add(reset);
    topPanel.add(quit);
    panel.add(topPanel, BorderLayout.NORTH);
    panel.add(trackPane, BorderLayout.CENTER);

    add(panel);
}
}




import javax.swing.JFrame;



public class HorseTester {
public static TrackPane t = new TrackPane();
public static void main(String[] args) {
    new HorseTester();
}

public HorseTester() {
    JFrame frame = new HorsePanel(t);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}
}

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class HorseThread implements Runnable {

public static final int X_START = 10;
public static final int Y_START = 20;
private boolean RUNNING = true;
public int FINISH_LINE = 450;
private Horse horse;
private int xpos, ypos;
private TrackPane track;
public JFrame frame = new JFrame();
public int id;

public HorseThread(TrackPane track, int offset) {
    xpos = X_START;
    id = offset;
    // Spaces the horses apart
    ypos = Y_START * offset * 3;
    horse = new Horse(xpos, ypos);
    this.track = track;
}


public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    horse.draw(g2);
}

/**
 * Run method that thread executes and makes horses go across the screen
 * racing.
 */
public void run() {

    while (RUNNING) {

            //varying the x position movement
            horse.setX(xpos += (int) (Math.random() * 10 + 1), id);
            // Sleeping the thread
            track.repaint();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (xpos >= FINISH_LINE) {
                RUNNING = false;
            }


        }
    }
}




public class Horse {

private int xTop, xStart;
private int yTop, yStart;
public static final int RING_WIDTH = 20, FINISH_LINE=450;
public JFrame frame = new JFrame();
public Lock lockThing = new ReentrantLock();

public Horse(int x, int y) {
    xTop = x;
    yTop = y;
    xStart = x;
    yStart = y;
}



public void setX(int dx, int id) {
    try{
        lockThing.lock();
        xTop=dx;
        if (dx >= FINISH_LINE){
            JOptionPane.showMessageDialog(frame, id + " Won");
        }

    }finally{ lockThing.unlock();}
}

public void draw(Graphics2D g2) {
    Ellipse2D.Double horse = new Ellipse2D.Double(xTop, yTop, RING_WIDTH,
            RING_WIDTH);
    g2.setColor(Color.RED);
    g2.fill(horse);
    g2.setColor(Color.BLUE);
    g2.draw(horse);
}
}



public class TrackPane extends JPanel {

private static final int NUM_OF_HORSES = 5;

private ArrayList<HorseThread> horses = new ArrayList<HorseThread>();
private ArrayList<Thread> threads = new ArrayList<Thread>(25);

public TrackPane() {
    setBackground(Color.WHITE);
    reset();
}

public void reset() {
    // Should dispose of any running threads...
    horses.clear();
    // Allocating the memory for horses
    for (int i = 0; i < NUM_OF_HORSES; i++) {
        horses.add(new HorseThread(this, i + 1));
    }
}

public void start() {
    // Should dispose of any running threads...
    threads.clear();
    for (int i = 0; i < horses.size(); i++) {
        Thread thread = new Thread(horses.get(i));
        thread.start();
        threads.add(thread);
    }
}


@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    for (HorseThread horse : horses) {
        horse.paint(g);
    }
}

}

1 个答案:

答案 0 :(得分:1)

您需要在线程之间共享RUNNING变量

private boolean RUNNING = true;

最快的方法(但不是最好的方法)是将其更改为静态:

private static volatile boolean RUNNING = true;

更合适和有福的方法是创建一个将在您的线程之间共享的组件,并将负责同步。 弹出的另一件事是弹出窗口:

JOptionPane.showMessageDialog(new JFrame(), id + " Won");

在有人关闭它之前阻塞了一个线程,这阻止了你的线程将RUNNING设置为false。 移动此逻辑以运行HorseThread的方法并将其从Horse类中的setX方法中删除:

class HorseThread implements Runnable {

private static volatile boolean RUNNING = true;
public static final int X_START = 10;
public static final int Y_START = 20;
public int FINISH_LINE = 450;
private Horse horse;
private int xpos, ypos;
private TrackPane track;
public JFrame frame = new JFrame();
public int id;

public HorseThread(TrackPane track, int offset) {
    xpos = X_START;
    id = offset;
    // Spaces the horses apart
    ypos = Y_START * offset * 3;
    horse = new Horse(xpos, ypos);
    this.track = track;
}


public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    horse.draw(g2);
}

/**
 * Run method that thread executes and makes horses go across the screen
 * racing.
 */
public void run() {

    while (RUNNING) {

        //varying the x position movement
        horse.setX(xpos += (int) (Math.random() * 10 + 1), id);
        // Sleeping the thread
        track.repaint();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (xpos >= FINISH_LINE) {
            RUNNING = false;
            JOptionPane.showMessageDialog(new JFrame(), id + " Won");
        }


    }
    }
}



class Horse {

private int xTop, xStart;
private int yTop, yStart;
public static final int RING_WIDTH = 20, FINISH_LINE=450;
public JFrame frame = new JFrame();
public Lock lockThing = new ReentrantLock();

public Horse(int x, int y) {
    xTop = x;
    yTop = y;
    xStart = x;
    yStart = y;
}



public void setX(int dx, int id) {
    try{
        lockThing.lock();
        xTop=dx;

    }finally{ lockThing.unlock();}
}

public void draw(Graphics2D g2) {
    Ellipse2D.Double horse = new Ellipse2D.Double(xTop, yTop, RING_WIDTH,
            RING_WIDTH);
    g2.setColor(Color.RED);
    g2.fill(horse);
    g2.setColor(Color.BLUE);
    g2.draw(horse);
    }
}