【问题标题】:how to restart a thread如何重新启动线程
【发布时间】:2011-01-05 10:00:00
【问题描述】:

我尝试编写一个文件监视器,它会检查文件是否添加了新行,监视器实际上是一个线程,它会一直通过随机访问文件读取该行。

这是监控核心代码:

public class Monitor {
    public static Logger                                    log             = Logger.getLogger(Monitor.class);
    public static final Monitor             instance        = new Monitor();
    private static final ArrayList<Listener>    registers       = new ArrayList<Listener>();

    private Runnable                                        task            = new MonitorTask();
    private Thread                                          monitorThread   = new Thread(task);
    private boolean                                         beStart         = true;

    private static RandomAccessFile                         raf             = null;
    private File                                            monitoredFile   = null;
    private long                                            lastPos;

    public void register(File f, Listener listener) {
        this.monitoredFile = f;
        registers.add(listener);
        monitorThread.start();
    }

    public void replaceFile(File newFileToBeMonitored) {
        this.monitoredFile = newFileToBeMonitored;

        // here,how to restart the monitorThread?
    }

    private void setRandomFile() {
        if (!monitoredFile.exists()) {
            log.warn("File [" + monitoredFile.getAbsolutePath()
                    + "] not exist,will try again after 30 seconds");
            try {
                Thread.sleep(30 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            setRandomFile();
            return;
        }
        try {
            if (raf != null) {
                raf.close();
                lastPos = 0;
            }
            raf = new RandomAccessFile(monitoredFile, "r");
            log.info("monitor file " + monitoredFile.getAbsolutePath());
        } catch (FileNotFoundException e) {
            // The file must exist now
        } catch (IOException e) {}
    }

    private void startRead() {
        beStart = true;
        String line;
        while (beStart) {
            try {
                raf.seek(lastPos);
                while ((line = raf.readLine()) != null) {
                    fireEvent(new FileEvent(monitoredFile.getAbsolutePath(),
                            line));
                }
                lastPos = raf.getFilePointer();
            } catch (IOException e1) {}
        }
    }

    private void stopRead() {
        this.beStart = false;
    }

    private void fireEvent(FileEvent event) {
        for (Listener lis : registers) {
            lis.lineAppended(event);
        }
    }

    private class MonitorTask implements Runnable {
        @Override
        public void run() {
            stopRead();

            //why putting the resetReandomAccessFile in this thread method is that it will sleep if the file not exist.
            setRandomFile();
            startRead();
        }

    }

}

这是一些帮助类:

public interface Listener {
    void lineAppended(FileEvent event);
}


public class FileEvent {
    private String  line;
    private String  source;

    public FileEvent(String filepath, String addedLine) {
        this.line = addedLine;
        this.source = filepath;
    }
    //getter and setter

}

这是一个调用监视器的例子:

public class Client implements Listener {
    private static File f   = new File("D:/ab.txt");

    public static void main(String[] args) {
        Monitor.instance.register(f, new Client());
        System.out.println(" I am done in the main method");
        try {
            Thread.sleep(5000);
            Monitor.instance.replaceFile(new File("D:/new.txt"));
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public void lineAppended(FileEvent event) {
        String line = event.getLine();
        if (line.length() <= 0)
            return;
        System.err.println("found in listener:" + line + ":" + line.length());
    }
}

现在,我的问题是,如果我只是调用,代码运行良好:

Monitor.instance.register(file,listener);

这将监视文件的行追加,并通知侦听器。

但是当我调用时它不起作用:

Monitor.instance.replaceFile(anotherfile);

这意味着我想监视另一个文件而不是以前。

所以在我的监视器中我必须重新启动线程,如何实现?

我试过了:

monitorThread.interruppt();

它不工作。

谁能帮我修好或者告诉我怎么做?

谢谢。

在我问之前,我已经在谷歌上搜索了“重启 java 线程”,所以我知道无法重启死线程,但我的线程不会返回,所以我认为可以重启。

【问题讨论】:

    标签: java multithreading restart


    【解决方案1】:

    您无需重新启动线程,而是在每次要启动线程时创建一个新线程。

    更好的选择可能是使用 Executors.newCachedThreadPool(),它为您提供了一个线程池,将为您启动/回收。

    顺便说一句:您使用递归而不是循环来轮询文件是否存在。使用递归可能意味着如果您等待太久,它将引发 StackOverflowError。恕我直言,您根本不应该等待,轮询线程应该反复尝试打开文件,直到它被告知停止(或文件出现)

    您当前的实现还意味着,如果文件被替换,无论如何您都必须在后台线程中重新打开该文件。

    【讨论】:

    • 其实你说的正是我想要的。但是我现在不知道使用executeService,应该在thread方法中放入哪些逻辑?
    • 您可以将您的任务(可运行)提交()到池中。当他们完成时,线程会回到池中,如果一分钟不使用就会退出。根据需要添加新线程。
    • 感谢您的好意。这是我的新代码。 dpaste.de/8Z6N 但是提交新任务时不能取消之前的任务。
    • 取消任务只会阻止它启动,并可选择设置中断标志。除非您的任务被设计为被中断,否则它们将一直运行到完成。
    【解决方案2】:

    我没有解释,只是编写了一个骨架示例。我没有很好地测试它,但它可能有一些用处。

    为了监控一个(另一个)文件,只需创建一个新的 Monitor,将它传递给 ScheduledExecutorService。启动和停止监控很简单。您可以(应该)为多个监视器重用相同的执行程序。

    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public interface Event
    {
    }
    
    public interface Listener
    {
        void handle(Event event);
    }
    
    public class Monitor
    {
        private static final int CHECK_EVERY_SECONDS = 10;
        private static final int RECHECK_AFTER_IF_NOT_EXISTS_SECONDS = 30;
    
        private File file;
        private ScheduledExecutorService executor;
        private boolean active;
        private List<Listener> listeners;
    
        public Monitor(File file, ScheduledExecutorService executor)
        {
            super();
            this.file = file;
            this.executor = executor;
            listeners = new ArrayList<Listener>();
        }
    
        public synchronized void start()
        {
            if (active)
            {
                return;
            }
            active = true;
            executor.execute(new Runnable()
            {
                public void run()
                {
                    synchronized (Monitor.this)
                    {
                        if (!active)
                        {
                            System.out.println("not active");
                            return;
                        }
                    }
                    if (!file.exists())
                    {
                        System.out.println("does not exist, rescheduled");
                        executor.schedule(this, RECHECK_AFTER_IF_NOT_EXISTS_SECONDS, TimeUnit.SECONDS);
                        return;
                    }
                    Event event = doStuff(file);
                    System.out.println("generated " + event);
                    updateListeners(event);
                    System.out.println("updated listeners and rescheduled");
                    executor.schedule(this, CHECK_EVERY_SECONDS, TimeUnit.SECONDS);
                }
            });
        }
    
        private Event doStuff(final File file)
        {
            return new Event()
            {
                public String toString()
                {
                    return "event for " + file;
                }
            };
        }
    
        public synchronized void stop()
        {
            active = false;
        }
    
        public void addListener(Listener listener)
        {
            synchronized (listeners)
            {
                listeners.add(listener);
            }
        }
    
        public void removeListener(Listener listener)
        {
            synchronized (listeners)
            {
                listeners.remove(listener);
            }
        }
    
        private void updateListeners(Event event)
        {
            synchronized (listeners)
            {
                for (Listener listener : listeners)
                {
                    listener.handle(event);
                }
            }
        }
    
        public static void main(String[] args) throws IOException
        {
            ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
            File file = new File("test.png");
            Monitor monitor = new Monitor(file, executor);
            monitor.addListener(new Listener()
            {
                public void handle(Event event)
                {
                    System.out.println("handling " + event);
                }
            });
            monitor.start();
            System.out.println("started...");
            System.in.read();       
            monitor.stop();
            System.out.println("done");
            executor.shutdown();
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      【讨论】:

        【解决方案4】:

        我假设你回答了你的问题

        无法重启死线程

        此链接可能对您有所帮助How to restart thread in java?

        【讨论】:

          【解决方案5】:

          Java 中的线程无法重新启动。每次您需要重新启动线程时,您必须创建一个新线程。

          也就是说,你可能想看看:

          private void setRandomFile() {
                  if (!monitoredFile.exists()) {
                      log.warn("File [" + monitoredFile.getAbsolutePath()
                              + "] not exist,will try again after 30 seconds");
                      try {
                          Thread.sleep(30 * 1000);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                      setRandomFile();
                      return;
                  }
          // ....
          }
          

          如果文件不存在,则在这里休眠 30 秒,然后递归调用相同的函数。现在,我不知道您有什么业务需求,但是如果此递归运行的时间足够长,您将耗尽堆栈空间。也许你会更好地使用while循环,甚至更好,像Semaphore这样的小同步。

          【讨论】:

            猜你喜欢
            • 2015-10-20
            • 2012-03-25
            • 2020-08-22
            • 1970-01-01
            • 1970-01-01
            • 2010-12-25
            • 1970-01-01
            相关资源
            最近更新 更多