Как перезапустить поток в Java?

Я создал программу, которая ищет файлы в исходной папке. Если он находит какой-либо файл, он обрабатывает этот файл и перемещает его в папку назначения, а затем ищет новый файл в исходной папке. Он должен постоянно проверять исходную папку для файла.

Я использовал поток для поиска файлов в исходной папке. Проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда во время обработки файла возникает какое-либо исключение, поток останавливается. Я хочу, чтобы поток работал даже в случае возникновения исключения. Он должен переместить файл, вызвавший ошибку, в другую папку и найти новый файл в исходной папке. Как я могу заставить поток продолжать работать?

Например:

public void run() {
    try {
        searchfile();
    }
    catch(Exception e) {
        e.printStackTrace();
    }
}

public void searchfile(){
  ...
}

Обновлять:

Я должен быть более ясным в своем вопросе. Фактически существует 4 исходные папки и 4 целевые папки. Я должен выполнить одну и ту же операцию в каждой паре источника и назначения. Итак, я создал 4 потока в одном классе и выполняю операцию в отдельном классе.

class MainClass
{
   public static void main(String[] args){
      for(int i=0;i<4;i++){
         SearchClass search = new SearchClass();
         Thread thread = new Thread(search);
         thread.start();
     }
   }   
}

class SearchClass
{
   public void run() {
   try {
      searchfile();
   } catch(Exception e) {
      e.printStackTrace();
   }
}

public void searchfile(){ ... } }

Весь поток не перестанет работать, даже если он поймал какое-либо исключение в середине. Как я могу это сделать?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
0
16 114
8

Ответы 8

Если поток умирает из-за неперехваченного исключения, ответ прост: перехватите исключение в подходящем месте, чтобы продолжить работу. Либо перехватите исключение в своем методе searchfile, либо заставьте метод run вызывать searchfile в цикле.

Внутри вашего улова вы можете переместить файл в папку ошибок, затем создать новый объект того же потока и запустить его снова.

если я не понял вас неправильно, в вашем коде отсутствует характер "продолжать работу", т.е. вам нужно где-то создать цикл:

public static void main(String[] args){

    ExecutorService service = Executors.newFixedThreadPool(4);

    // for each of your 4 folders
    while (true) {
        Future<File> searchResult = service.submit(new SearchTask());
        try {
          File foundFile = searchResult.get();
          // handle found file
        } catch (Exception e) {
          //    handle exception
        }
    }
}

private static class SearchTask implements Callable<File> {

    @Override
    public File call() {
      return searchFile();
    }

    public File searchFile() {
      // search & return found file
    }

}

обратите внимание, что это просто очень простое расширение вашего примера. по-прежнему отсутствует параметризация SearchTask, чтобы быть конкретной для папки, обработки файлов и исключений и т.д., как упоминалось в предыдущих ответах, ваша SearchTask должна реализовывать Runnable (я предпочитаю Callable ...), и IMHO это всегда лучше использовать ExecutorService, а не создавать потоки вручную. надеюсь это поможет...

вы сказали, что во время файлового процесса может возникнуть исключение, поэтому я помещаю processFile() в блок try-catch. но если он может быть брошен во время поиска, вы также можете поместить его в пробную ловушку.

public void run() {
    while(!terminated) {    
        findNextFile();
        try {
            processFile();
        } catch {
            // handle error
        }
    }
}

Если вы хотите, чтобы ваш поток продолжал работать, используйте цикл.

public void run() {
   while(!Thread.interrupted())
      try {
           searchfile();
      }
      catch(Exception e) {
          e.printStackTrace();
      }
}

Вот мои предположения, основанные на вашем вопросе и ваших пояснениях:

  • Каждый поток в методе run() вызывает searchfile() только один раз, а не в цикле.
  • в вашем методе searchfile() есть цикл, и вы хотите, чтобы этот цикл продолжал работать, даже если в нем возникло исключение.
  • у вас есть способ инициализировать каждый поток, который вы нам не показываете (и это не очень важно для этого конкретного quiestion)
  • searchfile() не заявляет, что выкидывает какие-либо Exception
  • Вы не используете платформу ведения журнала, а вместо этого используете System.out (хотя использование среды ведения журнала - действительно хорошая идея.
  • Java 5 в порядке (иначе вам придется использовать другой цикл for() ниже

Исходя из этих предположений, вы не хотите планировать обнаружение Exception в вашем методе run(), кроме как с целью регистрации того, что что-то пошло не так:

public void run() {
    try {
        searchfile();
    } catch (RuntimeException e) {
        System.out.println("Something went very wrong!  Unexpected RuntimeException");
        e.printStackTrace();
    }
}

Обратите внимание, что код перехватывает RuntimeException. Всегда выбирайте наиболее подходящий Exception, который сделает то, что вам нужно. Тогда вам понадобится что-то вроде следующего в вашем методе searchfile():

File[] files = directory.listFiles();
for (File file : files) {
    try {
        // Do your normal file/directory processing here
    } catch (Exception e) {
        System.out.println("Exception processing file " + file.getName() + " " + e);
        // Move "file" to another area
    }
}

Поскольку вы захватываете неожиданные Exception в основном цикле вашего Thread, ваш поток продолжит обработку после обработки Exception.

Я не совсем уверен, что это сработает, но попробую.

public void run() {
    try {
        searchFile();
    } catch(Exeption e) {
        e.printStackTrace();
        if (!Thread.currentThread().isAlive())
            Thread.currentThread().start();
    }
}

Вы можете легко найти обходной путь. Просто запустите необходимую логику несколько раз и завершите работу по некоторым критериям.

public class ThreadRestartWorkaround extends Thread {

public static void main(String[] args) {
    ThreadRestartWorkaround th = new ThreadRestartWorkaround(5);
    th.start();
}

private int maxCycles;
private int currentCycle;

public ThreadRestartWorkaround(int maxCycles) {
    this.maxCycles = maxCycles;
}

@Override
public void run() {
    while(executeSomeLogicUntilReachingTheLimit());
    System.out.println("Finished due to exceeding the maxCycles config");
}

private boolean executeSomeLogicUntilReachingTheLimit() {
    currentCycle++;
    System.out.println("Executing logic for " + currentCycle + " time");
    return currentCycle < maxCycles;
}
}

И на выходе

Executing logic for 1 time
Executing logic for 2 time
Executing logic for 3 time
Executing logic for 4 time
Executing logic for 5 time
Finished due to exceeding the maxCycles config

Другие вопросы по теме