2016-07-12 3 views
0

У меня случается, что трудно реплицировать ошибку, где висит одна из моих нитей.Java nio: многопоточность с DirectoryStream

  • Веб-паук прячет html-файлы в каталог.
  • Поток для обработки файлов считывает файлы в каталоге, обрабатывает их по одному и перемещает их.

Поскольку файл перемещения файлового процессора (по логической необходимости) может возникать только тогда, когда файл уже находится в каталоге, процесс чтения файла файлового процессора является асинхронным и вряд ли приведет к зависанию.

HOWEVER, поток файлового процессора также сканирует каталог, и это может произойти, поскольку поток веб-паука сохраняет файл в каталоге.

ВОПРОС: Если файл сохранен в этом каталоге при вызове следующего метода чтения, вызывает ли это зависание? (Честно говоря, я не понимаю, как это возможно, но, возможно, именно поэтому у меня есть ошибка).

Если да, то как решить проблему?

private void listFiles(Path path) 
{ 
    Log.getLogger().debug("started ......"); 
    try (DirectoryStream<Path> stream = Files.newDirectoryStream(path)) 
    { 
     for (Path entry : stream) 
     { 
      if (Files.isDirectory(entry)) 
      { 
       listFiles(entry); 
      } 
      else 
      { 
       files.add(entry); 
      } 
     } 
    } 
    catch (Exception e) 
    { 
     Log.getLogger().error(e.getMessage(), e); 
    } 
    Log.getLogger().debug("done"); 
} 
+0

Использование * один * 'ReentrantLock'. Вызов 'lock()' при записи ваших файлов 'unlock()' когда вы закончите. Затем на другой Thread вызовите 'lock()' перед выполнением сканирования/копирования и 'unlock()' когда это будет сделано. Это должно дать вам представление о том, связано ли это с потоками, мешающими друг другу в работе или нет. Это предотвратит выполнение потоками работы, когда другой поток приобрел блокировку в это время. – Selim

+0

Я попробую. Вы хотите опубликовать это как ответ? Даже если это не решит мою проблему, это хороший совет и необходимый диагностический шаг. – Jake

ответ

0

Чтобы избежать темы от вмешательства в работу друг друга семафор (или мьютекс в его простейшей форме) следует использовать. Полупафоры могут быть приобретены потоком для запуска кода в так называемом критическом разделе . Код в этом разделе может, например, получить доступ к ArrayList. Если несколько потоков обращаются к этому списку и добавляют и удаляют элементы из него, вы в конечном итоге получите ConcurrentModificationException. В других случаях вы не получите исключения вообще, но ваша программа может делать неожиданные вещи (например, the lost-update problem).

Если вы приобрели блокировку каждый раз, когда вы обращаетесь к критическому разделу, другие потоки не смогут получить доступ к общему ресурсу (список в этом случае или каталог в вашем случае).

Для достижения этого поведения, вы можете использовать классы, реализующие lock interface, создать объект и использовать его как замок, как так:

Object lock = new Object(); 

synchronized(lock) { 
    // do critical work here 
} 

Третий и, вероятно, наиболее неэффективен (но простой) путь - использовать ключевое слово synchronized для ваших методов. За один раз можно вызывать только один метод, который объявляется как синхронизированный внутри класса.

+0

. Здесь нет проблем с одновременной модификацией, есть ли? Один поток читается из каталога. Другим может быть добавление файлов синхронно. – Jake

+1

Как указано в моем ответе, это не обязательно должно быть «ConcurrentModificationException», это может быть даже вообще не исключение **, но какое-то странное и неожиданное поведение. – Selim

Смежные вопросы