我有2个线程在运行。一个是TimeStepThread
,另一个是CarThread
。
CarThread
每500毫秒运行一次。 TimeStepThread
以我给出的任何间隔运行。现在,每隔500毫秒,CarThread
更新道路上汽车位置的移动。每次调用TimeStepThread
时,我想获得该汽车位置值。例如,我有1辆汽车,无论如何每500毫秒更新一次,但每2秒我想设置一个汽车位置的标签。
我的课程设置如下:
Simulation
班级有TimeStepThread
和CarThread
。在我的Simulation
(或相反的框架)中,我希望在每个时间间隔更新汽车位置的值。所以每2000毫秒,我需要更新一些东西/返回到Simulation类中的东西。
除了我不知道如何做到这一点。由于我的主题位于Simulation
内,我无法真正从Simulation
调用run()
方法,更不用说它会有点混乱。听众,也许吧?
编辑:我已经可以在时间步长线程中访问汽车了。这不是问题。我正在使用一个容纳汽车的容器类,两个线程都可以访问,CarThread
也会更新它。我的问题是,每次调用TimeStepThread时,每次调用TimeStepThread时,Simulation类都会有一个更新的String,或者每次调用TimeStepThread时都会更新一个Frame标签。
答案 0 :(得分:1)
两个类中的两个类都需要访问汽车列表。
在这种情况下,汽车是汽车类的实例。
时间步骤线程有一个实现其工作的类。 (这是阅读汽车的位置。)
汽车线程有一个实现其工作的类。 (这是更新职位。)
每个执行类型类都将访问汽车对象,以使用位置更改信息更新它们或读出任何内容。例如,您将必须synchronize
访问该位置的汽车类(或下面提到的汽车容器)中的实例方法,因此各个线程不会相互踩。
这里有两种类似的方法。
1)每次创建汽车时,都会将其传递给两个工作类中的每一个。他们每个人都保留着自己所有车辆的内部清单。如果你摆脱了汽车,你必须告诉他们两个。
2)在开始时,您将为两个工作类中的每一个提供对汽车容器类的引用。也许只是一个列表 - 一个并发列表。也许是一个自定义类。当您创建汽车时,您告诉汽车集装箱类(通过添加它)。当你失去一辆车时,你也可以告诉它。
对于Simulation类,您希望在汽车位置发生变化时通知它。同样有两种方式,但它们是相似的。
在这两种情况下,您都必须将模拟类实例传递给正在进行更新的类。模拟类有一个方法,比如更新类在完成更新后调用的updateCar()
。
1)版本1 - 对模拟类实例的调用仅告诉它某些内容已发生变化。模拟类中的代码将识别已更改的内容并处理它,或者只更新所有内容。
2)版本2 - 对模拟类实例的调用将包括已更改的任何汽车的列表。模拟类不必搜索以查找更改的内容 它只能更新变化的东西。
棘手的部分是你必须记住那些对更新方法的调用是在更新线程中发生的。因此,例如,如果您使用Swing更新屏幕上的文本,则必须使用SwingWorker来获取事件线程中发生的更新。
如果你无法将这项工作转移到一个安全的线程,你必须确保所有正确的事情是并发或同步的,这样它们就不会相互踩踏。
答案 1 :(得分:0)
您可以在ConcurrentLinkedQueue
类中放置Simulation
- Car
线程将位置更新发送到队列。然后Timestep
线程处理所有位置更新(队列poll
,直到它返回空)并放置标签。
或者,您可以在BlockingQueue
类中放置Simulation
,并从队列中连续take
创建一个帖子并更新位置信息。
通过这种方式,您可以根据需要添加其他汽车,而无需更改Simulation
代码 - 所有汽车都将其更新发送到同一个队列。
答案 2 :(得分:0)
我认为听取汽车进步是最好的方法。你可以像
public interface CarProgressListener {
void positionChanged(Position currentPosition);
}
然后让您的TimestepThread
实现此界面并在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;
}
}
所以,现在在你的Simulation
课程中你需要有类似
...
Position initialPosition = // get it from somewhere.
CarThread car = new CarThread(initialPosition);
TimestepThread timestepThread = new TimestepThread(initialPosition);
car.addListener(timestepThread);
...
答案 3 :(得分: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()));
}
}
}
}
}