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

Java定时器仅触发一次(仅服务器问题),java,windows,server,hardware,Java,Windows,Server,Hardware,好的,这是一个奇怪的问题,它似乎不是一个编码问题。我的家用电脑和服务器电脑(都运行windows pro)上都安装了Intellij。我打开遥控器,把它并排放在一起。两者都使用Intellij open,并且都使用相同的复制和粘贴代码。在我的家用电脑上,这个代码工作得很好,每60秒就会触发一次。但在服务器计算机上,它只启动一次,不会再次启动。我把它打包到一个罐子里,然后运行罐子和同样的东西,它运行一次,再也不会运行了。这是代码 public class BackupTask extends Ti

好的,这是一个奇怪的问题,它似乎不是一个编码问题。我的家用电脑和服务器电脑(都运行windows pro)上都安装了Intellij。我打开遥控器,把它并排放在一起。两者都使用Intellij open,并且都使用相同的复制和粘贴代码。在我的家用电脑上,这个代码工作得很好,每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();
        }
    }
}
公共类备份任务扩展TimerTask{
私有静态final ThreadLocal df=new ThreadLocal(){
@凌驾
受保护的日期格式初始值(){
返回新的简化格式(“yyyy-MM-dd-HH_-MM_-ss”);
}
};
公开募捐{
试一试{
File src=新文件(“C:\\Users\\justi\\Desktop\\Server\\Saved”);
File dest=new File(“\\\\READYSHARE\\USB\u Storage\\Backups\\”+df.get().format(Calendar.getInstance().getTime());
如果(!dest.exists()){
dest.mkdir();
}
复制文件夹(src、dest);
}捕获(例外e){
System.out.println(“错误:+e”);
}
}
公共静态void copyFolder(文件src、文件dest)
抛出IOException{
if(src.isDirectory()){
//如果目录不存在,请创建它
如果(!dest.exists()){
dest.mkdir();
}
//列出所有目录内容
字符串文件[]=src.list();
用于(字符串文件:文件){
//构造src和dest文件结构
文件srcFile=新文件(src,File);
文件destFile=新文件(dest,File);
//递归拷贝
copyFolder(srcFile、destFile);
}
}否则{
//如果是文件,则复制它
//使用字节流支持所有文件类型
InputStream in=新文件InputStream(src);
OutputStream out=新文件OutputStream(dest);
字节[]缓冲区=新字节[1024];
整数长度;
//以字节为单位复制文件内容
而((长度=in.read(缓冲区))>0){
out.write(缓冲区,0,长度);
}
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);
    }
}
公共类自动备份{
//定时器;
private final ScheduledExecutorService scheduler=Executors.newScheduledThreadPool(1);
两次保存之间的私有最终整数时间=60;
公共自动备份(){
final ScheduledFuture beeperHandle=scheduler.scheduleAtFixedRate(新备份任务(),10,两次保存之间的时间,时间单位为秒);
}
公共静态void main(字符串[]args){
新的自动备份();
//定时器=新定时器();
//timer.schedule(新备份任务(),1000,60*1000);
}
}

这个程序只是一个非常简单的复制和粘贴从一个位置到另一个预定的时间间隔。我也尝试过以管理员的身份运行Intellij,我只是不知道为什么会发生这种情况。服务器计算机有一个核心i5-4690k、Micro-ITX千兆字节超耐用GA-H97N-WIFI H97主板和16千兆内存。请告诉我是否还有其他有用的信息。

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

Executors.newScheduledThreadPool(1);
此单线程将用于执行您的Runnable。然后,您计划以固定速率运行,先在10秒后运行,然后每60秒运行一次:

scheduler.scheduleAtFixedRate(new BackupTask(), 10, 60, TimeUnit.SECONDS);
现在,因为executor中只有一个线程可以运行可运行程序,所以当备份任务由于任何原因挂起时,或者可能执行更长的时间时,下一次执行将延迟到第一次执行完成时。您正在进行网络备份,因此问题可能与网络有关。例如,在相同的场景中,执行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");
    }
}
另外,我对您的代码有几点意见:

您的备份任务将扩展TimerTask。这是不必要的。它实现Runnable就足够了

当您从流中写/读时,您应该始终确保在finally部分中关闭资源,或者使用try with resources(从Java7开始)。否则,您可能会永远打开文件

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

感谢您的建议/代码审查!我喜欢别人解释我做错了什么。当我回到家时,我将尝试实现这一点,我将确保在最终捕获中更改关闭的流,并用我发现的更新。非常感谢你的帮助!我甚至不知道从哪里开始寻找:),至少这给了我一些想法,尝试看看会发生什么。再次感谢!好吧,现在我承认这一点会觉得很愚蠢,但是。。。。在服务器和机器上进行测试时,我没有使用相同的数据集。回到家后,我意识到我要备份的文件真的很大。。。备份到网络驱动器大约需要10-15分钟。我甚至不知道我怎么没有注意到/想到这么简单的事情。最后感谢您对我们的帮助和建议。