JavaFx 在定时任务中使用线程池实现向线程中能够传值和获取返回值

xu.wang

发布于 2020.12.21 21:46 阅读 2950 评论 0

场景: 

      项目当中有一个需求,目的是通过串口服务器读取12个岗位上的PLC数据,并实时(每隔500ms)显示在界面当中。

方案:

      在需求中提到了每隔500ms,所以需要创建一个每隔500ms执行的定时任务。

      同时获取12个岗位中的PLC数据,则需要创建12个线程用来同步获取数据。

      首先创建定时任务:


//在主线程中开启定时任务,由于是在JavaFx的main中,故省略了JavaFx部分。
private static ScheduledService testScheduledService = null;
    /**
     * 不与JavaFX Application结合会报:Exception in thread "main" java.lang.IllegalStateException: Toolkit not initialized
     */
    private static void executeScheduledService(){

        //设置间隔500ms
        Integer time =  500;
        if(StringUtil.isNotEmpty(timeStr)) {
            time =Integer.parseInt (timeStr);
        }
        testScheduledService = new ScheduleService();
        // 设置线程池,restart会尝试重用线程
        testScheduledService.setExecutor(Executors.newFixedThreadPool(12));
        // 延时1s开始
        testScheduledService.setDelay(Duration.millis(1000));
        // 间隔1s执行
        testScheduledService.setPeriod(Duration.millis(time));
        testScheduledService.start();

        // delay和period的设置时间经过之后,ScheduledService Delay Timer线程才会靠cancel()结束
//        testScheduledService.cancel();
//        testScheduledService.restart();
    }


// 执行任务的类
public class ScheduleService extends ScheduledService<Void> {

@Override
    protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() {
               System.out.println("ScheduledService_Task begin");
                   //定时功能
                    getData();
                
                return null;
            }
        };
    }
}

  第二步在定时任务中创建线程获取数据并更新UI,下面给出getData的详细过程:

 public void getData() {
        //创建线程池
        ExecutorService executorService=Executors.newCachedThreadPool();
        
        System.out.println("开始线程1");
        Callable<ModBusData> callable=new GetWaterPressThread(2);
        Future future=executorService.submit(callable);
        try {
            if(future.isDone()){
               System.out.println("线程1,isNotDone");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("开始线程2");
        Callable<ModBusData> callable2=new GetWaterPressThread(3);
        Future future2=executorService.submit(callable2);
        try {
            if(future2.isDone()){
               System.out.println("线程2,isNotDone");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

       //关闭线程池
        executorService.shutdown();


        Platform.runLater(new Runnable()
        {
            @SneakyThrows
            @Override
            public void run()
            {
              //高频率更新UI
               ModBusData modBusData1 = (ModBusData) future.get();
               ModBusData modBusData2 = (ModBusData) future2.get();
               updateUIData(modBusData1);
               updateUIData(modBusData2);
            }
        });

}

  重点:下面创建一个类实现 Callable,来解决向线程中传值和返回值的问题


import java.util.concurrent.Callable;

public class GetWaterPressThread implements Callable<ModBusData> {

    //岗位
    private Integer position;

   public GetWaterPressThread(Integer position){
       this.position = position;
   }

    @Override
    public ModBusData call() throws Exception {
       ModBusData modBusData = new ModBusData();
       modBusData.setNo(position+"");
       modBusData.setPress1(12.3f);
       //模拟一秒后才能获取到数据
       Thread.sleep(1000);
       return modBusData;
 

    }
}

 

以上为根据需求结合搜索完成的方案,其中会有一些问题,接下来还会继续学习。