4

我有 2 个线程正在运行。一个是a TimeStepThread,另一个是a CarThread。每CarThread500 毫秒运行一次。TimeStepThread以我给它的任何间隔运行。现在,每 500 毫秒,CarThread更新道路上汽车位置的移动。但是,每次TimeStepThread调用时,我都想获得该汽车位置值。例如,我有 1 辆汽车,无论如何每 500 毫秒更新一次,但每 2 秒我想设置一个带有该汽车位置的标签。

我的课程是这样设置的:

  1. Simulation班级有一个
  2. TimeStepThread和一个CarThread

在我的Simulation(或框架,更确切地说)中,我想在每个时间步长间隔更新汽车位置的值。所以每 2000 毫秒,我需要更新一些东西/返回一些东西到模拟类。

除了我不知道如何做到这一点。由于我的线程在里面 Simulation,我不能真正 Simulation从里面调用方法run(),更不用说它会有点乱。听众,也许?


编辑:我已经可以在时间步线程中访问汽车。这不是问题。我正在使用一个包含汽车的容器类,两个线程都可以访问并对其进行CarThread更新。我的问题是关于具有更新字符串的模拟类,每次调用 TimeStepThread 时,或更新帧标签,每次调用 TimeStepThread 时。

4

4 回答 4

1

两个线程中的两个类都需要访问汽车列表。

在这种情况下,汽车是汽车类的实例。

时间步长线程有一个实现其工作的类。(这是读取汽车的位置。)

汽车线程有一个实现其工作的类。(这是更新职位。)

每个执行类型类将访问汽车对象以使用位置更改信息更新它们或读出任何内容。例如,您将不得不synchronize使用汽车类(或下面提到的汽车容器)中的实例方法来访问该位置,这样各个线程就不会互相踩踏。

这里有两种类似的实现方式。

1) 每次您创建汽车时,您都会将其传递给两个工作类中的每一个。他们每个人都有自己的所有汽车的内部清单。如果你摆脱一辆车,你必须告诉他们两个。

2) 在开始时,您为两个工作类中的每一个提供对汽车容器类的引用。也许只是一个列表——不过是一个并发列表。也许是一个自定义类。创建汽车时,您告诉汽车容器类(通过添加它)。当你失去一辆车时,你也会告诉它。

至于模拟类,您希望在汽车位置发生变化时通知它。同样有两种方法,但它们是相似的。

在这两种情况下,您都必须将模拟类实例传递给正在进行更新的类。模拟类有一个方法,说updateCar()更新类一旦完成更新就会调用。

1) 版本 1 - 对模拟类实例的调用只告诉它发生了一些变化。模拟类中的代码将识别已更改的内容并进行处理,或者它只会更新所有内容。

2) 版​​本 2 - 对模拟类实例的调用将包括已更改的所有汽车的列表。模拟类不必搜索以查找更改的内容,它可以仅更新更改的内容。

棘手的部分是您必须记住,对更新方法的那些调用是在更新线程中发生的。因此,例如,如果您使用 Swing 更新屏幕上的文本,则必须使用 SwingWorker 来获取更新以在事件线程中发生。

如果您不能将该工作转移到安全线程,则必须确保所有正确的事情都是并发或同步的,这样它们就不会相互影响。

于 2013-05-20T15:30:39.550 回答
0

我认为您不需要列表或任何其他数据结构。它可以像这样简单:

public class Car

    private volatile int position;


    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }

}

public class CarThread extends Thread {

    private final Car car;

    public CarThread(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        Thread.sleep(500);
        car.setPosition(//whatever)
    }
}

public class TimeStepThread extends Thread {

    private final Car car;

    public CarThread(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        Thread.sleep(2000);
        int position = car.getPosition()

        // do stuff
    }
}

确保你将同一个 Car 实例传递给所有东西,你会没事的。

该答案还假设您不需要将所有位置更改排队,只有最近的位置才有意义,如果您使用它在地图或类似的东西上绘制汽车的位置,则合理的。

编辑

要将它们放在一起,请尝试以下操作:

public class TimeStepThread extends Thread {

    private final Car car;
    private final JFrame frame;


    public TimeStepThread(Car car, JFrame frame) {
        this.car = car;
        this.frame = frame;
    }

    @Override
    public void run() {
        while(true) {
            Thread.sleep(2000);
            EventQueue.invokeLater(new Runnable() {

                @Override
                public void run() {
                    frame.setTitle(Integer.toString(car.getPosition()));
                }
            }
        }
    }
}
于 2013-05-20T15:41:40.420 回答
0

You can put a ConcurrentLinkedQueue in the Simulation class - the Car thread sends position updates to the queue. The Timestep thread then processes all of the position updates (poll the queue until it returns empty) and places the labels.

Alternatively, you can put a BlockingQueue in the Simulation class, and have a thread continually take from the queue and update the position information.

This way you can add as may additional cars as you want without having to change the Simulation code - all of the cars send their updates to the same queue.

于 2013-05-20T15:28:06.883 回答
0

I think a listener for you car progress is the best approach. You could something like

public interface CarProgressListener {
    void positionChanged(Position currentPosition);
}

then make your TimestepThread implement this interface and register it at CarThread.

public CarThread extends Thread {
     private final Collection<CarProgressListener> progressListeners = new LinkedList<>();
     // other stuff
     public void addListener(CarProgressListener listener) {
         this.progressListeners.add(listener);
     }
}

public TimestepThread extends Thread implements CarProgressListener {
     private Position lastHeardCarPosition;

     // remenber to initiate this thread with the first car position.

     @Override
     public void positionChanged(Position currentPosition) {
         this.lastHeardCarPosition = currentPosition;
     }
}

So, now in your Simulation class you will need to have something like

...
Position initialPosition = // get it from somewhere.
CarThread car = new CarThread(initialPosition);
TimestepThread timestepThread = new TimestepThread(initialPosition);

car.addListener(timestepThread);
...    
于 2013-05-20T15:28:41.950 回答