Java 计时器仅触发一次(仅服务器问题)

Java Timer only fire once (server only issue)

好的,这是一个奇怪的问题,它似乎不是编码问题。我在家用电脑和服务器电脑上都安装了 Intellij(运行 windows pro)。我远程进入并并排放置。两者都打开了 Intellij,并且都具有相同的复制和粘贴代码。在我的家用电脑上这段代码运行良好,它每 60 秒触发一次。但是在服务器计算机上它会触发一次并且不会再次触发。我已经将它打包到一个罐子里,运行 罐子和同样的东西,它运行一次就再也不会运行了。这是代码。

public class BackupTask extends TimerTask {
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH_mm_ss");
        }
    };

    public void run() {
        try {
            File src = new File("C:\Users\justi\Desktop\Server\Saved");
            File dest = new File("\\READYSHARE\USB_Storage\Backups\" + df.get().format(Calendar.getInstance().getTime()));

            if(!dest.exists()){
                dest.mkdir();
            }

            copyFolder(src, dest);
        }catch(Exception e){
            System.out.println("Error: " + e);
        }
    }

    public static void copyFolder(File src, File dest)
            throws IOException{

        if(src.isDirectory()){

            //if directory not exists, create it
            if(!dest.exists()){
                dest.mkdir();
            }

            //list all the directory contents
            String files[] = src.list();

            for (String file : files) {
                //construct the src and dest file structure
                File srcFile = new File(src, file);
                File destFile = new File(dest, file);
                //recursive copy
                copyFolder(srcFile,destFile);
            }

        }else{
            //if file, then copy it
            //Use bytes stream to support all file types
            InputStream in = new FileInputStream(src);
            OutputStream out = new FileOutputStream(dest);

            byte[] buffer = new byte[1024];

            int length;
            //copy the file content in bytes
            while ((length = in.read(buffer)) > 0){
                out.write(buffer, 0, length);
            }

            in.close();
            out.close();
        }
    }
}

AutoBackup.java

public class AutoBackup {
//    Timer timer;

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private final int TIME_BETWEEN_SAVES = 60;

    public AutoBackup(){
        final ScheduledFuture<?> beeperHandle = scheduler.scheduleAtFixedRate(new BackupTask(), 10, TIME_BETWEEN_SAVES, TimeUnit.SECONDS);
    }

    public static void main(String[] args) {
        new AutoBackup();
//        Timer timer = new Timer();
//        timer.schedule(new BackupTask(), 1000, 60 * 1000);
    }
}

这个程序只是一个非常简单的复制,并按预定的时间间隔从一个位置粘贴到另一个位置。我也尝试过 运行 Intellij 作为管理员,我只是不知道为什么会发生这种情况。服务器计算机配备核心 i5-4690k、Micro ITX 技嘉超耐用 GA-H97N-WIFI H97 主板和 16 GB 内存。如果有任何其他信息可以帮助,请告诉我。

你描述的很奇怪,但我想出了一个案例,你的代码可能会失败。让我详细描述一下。您首先创建线程池大小为 1 的新计划执行程序:

Executors.newScheduledThreadPool(1);

这个单线程将用于执行您的 运行nables。然后你安排 运行nable 以固定速率,首先在 10 秒后 运行,然后每 60 秒:

scheduler.scheduleAtFixedRate(new BackupTask(), 10, 60, TimeUnit.SECONDS);

现在,因为您在执行器中只有一个线程可以 运行 您的 运行nables,当您的 BackupTask 由于任何原因挂起时,或者可能执行更长时间,下一次执行将是只要第一个完成就会延迟。您正在进行网络备份,因此问题可能与网络有关。举个例子——执行 close() 可能会导致代码等待网络超时(取决于超时值的长度),或者在相同的情况下执行 write(..)。

我的建议是在您的代码中加入一些调试语句(请参阅下面的代码)。我知道这可能会在应用程序控制台中产生一些垃圾,但如果您不想远程调试,这可能是找出代码错误的唯一方法。

public static void copyFolder(File src, File dest) throws IOException{
    if (src.isDirectory()) {

        //if directory not exists, create it
        if(!dest.exists()){
            System.out.println("Creating directory " + dest);
            dest.mkdir();
            System.out.println("Created directory ");
        }

        for (String file : src.list()) {

            File srcFile = new File(src, file);
            File destFile = new File(dest, file);

            System.out.println("Copying " + srcFile + " to " + destFile);
            copyFolder(srcFile,destFile);
            System.out.println("Copied " + srcFile + " to " + destFile);
        }

    }else{

        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dest);

        byte[] buffer = new byte[1024];

        System.out.println("Writing file " + src + " to " + dest);

        int length;
        //copy the file content in bytes
        while ((length = in.read(buffer)) > 0){
            out.write(buffer, 0, length);
        }

        System.out.println("Closing file " + src);
        in.close();

        System.out.println("Closing file " + dest);
        out.close();

        System.out.println("Writing file " + src + " to " + dest + " is done");
    }
}

此外,我对您的代码的几点评论:

您的 BackupTask 扩展了 TimerTask。这是不必要的。它实现Runnable就够了。

当你从流中 write/read 时,你应该始终确保在 finally 部分关闭你的资源,或者使用资源尝试(从 Java 7 向上)。否则,您可能会永远打开文件。

InputStream in = null;
OutputStream out = null;

byte[] buffer = new byte[1024];
int length;

try {
  in = new FileInputStream(src);
  out = new FileOutputStream(dest);
  while ((length = in.read(buffer)) > 0) {
    out.write(buffer, 0, length);
  }
} finally {
  if (in != null) {
    try {
      in.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  if (out != null) {
    try {
      out.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}