В моем previous question я был на простом упражнении, наблюдая за каталогом изменений файла. Я взял код от this oracle docs, и он работал без проблем, за исключением небольшого неконтролируемого предупреждения о броске, о котором я не знал.Смотреть каталог, используя запланированный исполнитель вместо жесткой петли в Java
Следующая проблема с этим кодом заключается в том, что он помещает жесткий цикл внутри потока, который блокирует, по крайней мере теоретически. Теперь я знаю, что если операционная система использует временную разбивку, даже жесткий цикл разделяется небольшими фрагментами, которые разделяют время процессора с другими потоками приложения, и на самом деле я могу делать всевозможные примеры, где жесткие циклы работающие в разных потоках, не блокируют друг друга (если они имеют одинаковый приоритет), даже на виртуальной машине, явно созданной только с одним ядром.
Однако язык Java не гарантирует, какой вид планирования он использует для управления потоками, если это временная нарезка или циклическая обработка; это зависит от реальной реализации VM и операционной системы. Поэтому совет, который я получаю при изучении предмета, заключается в написании кода так, как если бы он выполнялся при планировании потоков с циклическим циклом, таким образом избегая помещать жесткие петли в потоки, если только мой код не может постоянно отводить контроль над другими потоками с sleep()
, wait()
, yeld()
и т. д. (я могу думать о графическом интерфейсе, где основной поток - это тот, где жесткий цикл наблюдает за событиями, и отправляет управление обратно слушателям для их обработки).
В моем случае, однако, я не мог придумать способ скрыть поток после того, как он обработает изменение файла, или вернуть управление в основной цикл, поскольку основная идея в основном заключается в непрерывном спросите, есть ли изменения в файловой системе. Итак, к чему я пришел, это запланированный исполнитель, который регулярно называет наблюдательный поток. Ясно, что это компромисс между наличием «блокирующего» потока и немедленным уведомлением о произошедшем изменении файловой системы. Поскольку в реальном случае я собираюсь включить это упражнение, мне, вероятно, не понадобится немедленное уведомление, я доволен этим. Код очень прост:
// imports...
public class Main
{
public static FileSystem fs;
public static Path dir;
public static WatchService watcher;
public static WatchKey key;
public static void main(String[] args)
{
fs = FileSystem.getDefault();
dir = fs.getPath(".");
try {
watcher = fs.newWatchService();
dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
} catch (IOException e) {
System.err.println(e.getMessage());
return;
}
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable()
{
public void run()
{
Main.key = Main.watcher.poll();
if (null == Main.key)
return;
for (WatchEvent<?> event : Main.key.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW)
continue;
@SuppressWarnings("unchecked");
WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path file = ev.context();
System.out.println(file);
boolean valid = Main.key.reset();
if (!valid)
System.err.println("Invalid key!");
}
}
}, 0, 1, TimeUnit.SECONDS);
}
}
Так что мои вопросы:
ли я толкая это слишком далеко? Я имею в виду, действительно ли это хорошая практика, которая очень заботится о блокировании кода в потоках, или это реальные случаи, когда среза времени нет, так редко, что я могу безопасно помещать жесткий цикл внутри потока и, возможно, сделать это что-то вроде того, когда я знаю, что мой код будет запущен, возможно, на встроенном устройстве с гарантированным округлением?
Есть ли другой способ избежать жесткой петли в данном конкретном случае? Может быть, какое-то умное использование методов управления потоками (
sleep()
,wait()
и т. Д.), О которых я не могу думать?
Большое спасибо и извините за длинный пост.
Почему вы используете 'poll()'? 'take()' позволит избежать потери процессора. –
@RogerGustavsson Если я правильно понял документы, 'take()' (который я использовал в предыдущей версии этого кода) блокирует выполнение, ожидающее следующего ключа Watch, в то время как 'poll()' выталкивает следующие часы ключ или «null», если ни один не присутствует, и в любом случае немедленно возвращается. Поэтому кажется, что 'poll()' - это способ избежать ожидания. – swahnee
@swahnee Почему вы хотите избежать ожидания? Я думал, что это именно то, что вы хотите: пусть ваш поток ждет, пока не появится новый ключ часов. – isnot2bad