【问题标题】:TimerTask stops running after midnightTimerTask 在午夜后停止运行
【发布时间】:2021-10-15 07:56:49
【问题描述】:

我有一小部分程序有一个计时器,它每 15 分钟通过命令行 (fswebcam) 使用 USB 网络摄像头拍照。

代码是这样的:

public static final String HOME_DIR = System.getProperty("user.home") + "/";
public static final String PGP_DIR = HOME_DIR + "PGP/";

public static final String COLLECTION_DATA_DIR = PGP_DIR + "collectionData/";
public static final String SENSOR_CALIBRATION_DATA = PGP_DIR + "sensorCalibration/";
public static final String PICTURE_DIR = PGP_DIR + "pictures/";
public static final String ALARM_DIR = PGP_DIR + "alarms/";
private class PictureTakerTask extends TimerTask{
        Timer t;
        public void start(){
            if(t != null){
                t.cancel();
                t.purge();
                t = null;
                this.cancel();
            }
            t = new Timer(true);
            t.scheduleAtFixedRate(this, 0, 1000 * 60 * 15); //takes a picture every 15 minutes
        }

        public void stop(){
            if(running) return;
            if(t != null){
                t.cancel();
                t.purge();
                t = null;
            }
            this.cancel();
        }

        @Override
        public void run() {
            
            String filename = getPictureFilename();
            if(filename == null) return;
            Process p;
            try {
                CommIO.printLog("Taking a picture");
                String file;
                light.setGreenPWM(80);
                p = Runtime.getRuntime().exec("fswebcam -r 1920x1080 --no-banner -S 1 " + filename);
                p.waitFor();
                System.out.println ("picture taken with exit value: " + p.exitValue());
                p.destroy();
                light.setGreenPWM(0);
            } catch (Exception e) {
                e.printStackTrace();
                light.setGreenPWM(0);
            }
        }

        private String getPictureFilename(){
            //make folder if it doesn't exist already
            SimpleDateFormat justDate = new SimpleDateFormat("MM-dd-yy");
            String date = justDate.format(new Date());
            String s = PICTURE_DIR + date + "/";
            File picDir = new File(s);
            if(!picDir.exists()){
                if(picDir.mkdir()){
                    Alert alert = new Alert(AlertType.ERROR, "Couldn't make picture directory: " + s, ButtonType.OK);
                }
            }
            //find an unused filename
            String picFileName = s + "plant_01.jpg";
            File tempFile = new File(picFileName);
            int i = 1;
            while (tempFile.exists()) { //finds the next nonexistent name for data spreadsheet
                String num = i < 10 ? "0" + i : "" + i;
                picFileName = s + "plant_" + num + ".jpg";
                i++;
                tempFile = new File(picFileName);
                if(i > 10000) break;
            }
            return picFileName;
        }
    }

线程启动并正常工作,直到午夜。第二天就不能拍照了。我无法弄清楚为什么它会停止。如果我停止并重新启动任务,它将再次正常工作。如果我什至通过程序外的终端拍照,它会再次正常工作。它只会在第二天停止拍照。它甚至创建了第二天的文件夹,只是没有图片。没有错误消息(我可以找到)。

有人对此有任何想法或经验吗?在你说之前,不,我不能使用运动或 Cron,因为我需要与 run() 函数中的“light”对象同步。

【问题讨论】:

  • …或 Cron,因为我需要与 run() 函数中的“轻”对象同步。为什么,碰巧,cron 会有问题?您可以在 cron 脚本中设置灯光。另一个问题:你总是得到一个零的退出代码吗?
  • PICTURE_DIR 到底是什么?
  • java.util.Datejava.sql.Date?
  • util.Date。同样g00se,所讨论的“灯”实际上与串行端口相关联,并且在同一程序中的单独计时器(实际上是多个计时器)中频繁地(大约每秒一次)进行通信。我不想通过单独的程序来处理额外的资源/同步冲突问题,单独的计时器已经够头疼了。
  • @BasilBourque 编辑问题以包含目录。简化为“pihome”/PGP/pictures

标签: java raspberry-pi4


【解决方案1】:

您可以尝试将时间设置为上午 12:00:01 下午 11:59:59。我不确定这是否会解决它。一个while循环可以工作。

【讨论】:

  • 这似乎不是一个好方法。一方面,除非您将时钟调回某个时间点,否则系统时钟将每天进动 2 秒。
【解决方案2】:

回答我自己的问题。简单的错误,实际上:

if(picDir.mkdir()){
    Alert alert = new Alert(AlertType.ERROR, "Couldn't make picture directory: " + s, ButtonType.OK);
}

忘记了条件的否定。我通常每天运行该程序不止一次以检查其他更改,因此它第一次创建文件夹,使线程崩溃,并且在接下来的几次我启动程序时运行良好。但是当第二天到来时,它会发出警报并发脾气,因为它不在 FX 线程上。很难注意到,因为我什至忘了显示警报。

我喜欢 java-fx,但它有时会很挑剔。通过添加否定并将警报放入 Platform.runLater Runnable 来修复。

【讨论】:

  • 这是我的猜测。顺便说一句,您的代码还有更多的改进空间。我开始编写示例代码,但是在这里发布太多了。问题包括:(a) 您使用的日期时间类在几年前被 JSR 310 中定义的现代 java.time 类所取代。(b) TimerTaskTimer 是几年前之前被 Executors 框架取代。 (c) 您正在使用多年前被 NIO.2 取代的旧文件 I/O 类。 (d) 一些小问题包括用get… 命名一个方法,它的作用远不止访问一个字段。您的序列格式应该是 3 位数字。
猜你喜欢
  • 2016-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
  • 2017-10-18
  • 2015-09-17
  • 1970-01-01
  • 2018-07-19
相关资源
最近更新 更多