Java 每次线程执行其运行时获取值/返回某些内容

Java 每次线程执行其运行时获取值/返回某些内容,java,multithreading,return,frame,runnable,Java,Multithreading,Return,Frame,Runnable,我有两个线程在运行。一个是TimeStepThread,另一个是CarThread。 CarThread每500毫秒运行一次。TimeStepThread以我给定的任何间隔运行。现在,每500毫秒,CarThread就会更新道路上汽车位置的移动。然而,每次调用TimeStepThread时,我都想得到汽车位置值。例如,我有一辆车,不管怎样,每500毫秒更新一次,但每2秒我想用该车的位置设置一个标签 我的课程设置如下: public class TimeStepThread extends Thr

我有两个线程在运行。一个是
TimeStepThread
,另一个是
CarThread
CarThread
每500毫秒运行一次。
TimeStepThread
以我给定的任何间隔运行。现在,每500毫秒,
CarThread
就会更新道路上汽车位置的移动。然而,每次调用
TimeStepThread
时,我都想得到汽车位置值。例如,我有一辆车,不管怎样,每500毫秒更新一次,但每2秒我想用该车的位置设置一个标签

我的课程设置如下:

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()));
                }
            }
        }
    }
}
  • 模拟
    类具有
  • TimeStepThread
    CarThread
  • 在我的
    模拟中
    (或者更确切地说是在帧中),我希望在每个时间步间隔更新汽车位置的值。因此,每2000ms,我需要在模拟类中更新/返回一些内容

    只是我不知道怎么做。由于我的线程位于
    模拟
    中,因此我无法从
    运行()调用
    模拟
    方法,更不用说它会有点混乱。也许是听众



    编辑:我已经可以在timestep线程中访问汽车了。这不是问题。我正在使用一个容器类来保存这些汽车,两个线程都可以访问,
    CarThread
    也会更新它。我的问题是仿真类在每次调用TimeStepThread时都有一个更新的字符串,或者在每次调用TimeStepThread时都有一个更新的帧标签。

    您可以在
    仿真
    类中放置一个
    ConcurrentLinkedQueue
    -Car
    线程向队列发送位置更新。然后,
    Timestep
    线程处理所有位置更新(
    poll
    队列,直到它返回空)并放置标签

    或者,您可以将
    阻塞队列
    放入
    模拟
    类中,并让一个线程从队列中持续
    获取
    ,并更新位置信息


    通过这种方式,您可以根据需要添加更多的车辆,而无需更改
    模拟
    代码-所有车辆都会将更新发送到同一队列。

    我认为最好的方法是为您提供一个车辆进度监听器。你可以这样做

    public interface CarProgressListener {
        void positionChanged(Position currentPosition);
    }
    
    ...
    Position initialPosition = // get it from somewhere.
    CarThread car = new CarThread(initialPosition);
    TimestepThread timestepThread = new TimestepThread(initialPosition);
    
    car.addListener(timestepThread);
    ...    
    
    然后让您的
    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;
         }
    }
    

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

    在本例中,汽车是汽车类的实例

    时间步线程有一个实现其工作的类。(正在读取车辆的位置。)

    car线程有一个实现其工作的类。(正在更新位置。)

    每个执行类型类将访问car对象,以使用位置更改信息更新它们,或读取任何内容。例如,您必须
    同步
    car类(或下面提到的car容器)中访问该位置的实例方法,这样各个线程就不会相互重叠

    这里有两种类似的实现方法

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

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

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

    在这两种情况下,都必须将仿真类实例传递给正在进行更新的类。simulation类有一个方法,比如说
    updateCar()
    ,更新类在完成更新后调用该方法

    1) 版本1-对simulation类实例的调用只告诉它发生了变化。simulation类中的代码将识别发生了什么变化并进行处理,或者只是更新所有内容

    2) 版本2-对simulation类实例的调用将包括已更改的所有汽车的列表。simulation类不必搜索以查找更改的内容 而且它只能更新不断变化的事物

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


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

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

    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
        }
    }
    
    确保你把同一辆车传给所有人,你会没事的

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

    编辑

    要将所有这些放在一起,请尝试以下方法:

    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()));
                    }
                }
            }
        }
    }
    

    我的线程已经可以访问汽车对象。我的线程已经可以访问汽车对象了。把问题的措辞改了一点。对不起,那么我不明白这个问题。只要从TimeStepThread每隔2000ms调用getPosition(),您就会看到从CarThread计算的最新值。我不需要线程中的值,我需要帧jLabel中的值,每2000ms更新一次。