При попытке использовать семафор выполняется только один из моих потоков [закрыто] ⇐ JAVA
При попытке использовать семафор выполняется только один из моих потоков [закрыто]
Насколько я понимаю, java.util.concurrent.Semaphore позволяет мне указать, сколько потоков могут использовать ресурс одновременно. Поток может использовать Semaphore.acquireUninterruptible() для использования ограниченного числа «слотов» в семафоре. После завершения потока необходимо выполнить вызов Semaphore.release(), чтобы вернуть слот, чтобы другой ожидающий поток (acquireUninterruptible()) заставляет поток ждать) может захватить новый слот. Я осведомлен о политике справедливости, и порядок тем не имеет значения для моих целей. Важно то, что все потоки выполняются.
И в этом моя проблема — выполняется только один из потоков. Вот мой код.
import java.nio.file.Path; импортировать java.util.ArrayList; импортировать java.util.List; импортировать java.util.concurrent.Semaphore; общественный класс Главный { частный статический окончательный путь rootbarFolder = Path.of("C:", "Users"); частное логическое значение REATTEMPT_UPON_FAILURE = true; public static void main(final String[] args) выдает исключение { новый Главный(); } частный Main() выдает исключение { javax.swing.SwingUtilities .invokeLater ( () -> { javax.swing.JOptionPane.showMessageDialog(null, «Закройте это всплывающее окно, чтобы программа завершила работу в случае сбоя»); this.REATTEMPT_UPON_FAILURE = ложь; } ) ; окончательный список fooPathList = this.getListOfbarfooPaths(); окончательный List fooPathThreads = новый ArrayList(); окончательный семафор семафора = новый семафор (1, правда); KICK_OFF_THREADS: for (конечный путь fooPath: fooPathList) { конечный поток fooPathThread = this.createThread(семафор, fooPath); fooPathThreads.add(fooPathThread); семафор.acquireUninterruptible(); fooPathThread.start(); } ПРИСОЕДИНЯЙТЕСЬ_THREADS: for (последняя тема fooPathThread: fooPathThreads) { fooPathThread.join(); } } частный поток createThread (последний семафор семафора, окончательный путь fooPath) { возвращаться Нить .ofPlatform() .unstarted ( () -> { пытаться { INT код выхода = -1; while (exitCode!= 0 && this.REATTEMPT_UPON_FAILURE) { System.out.println("\n\nПопытка " + fooPath); окончательный процесс fooProcess = this.createzilklaquo(fooPath); exitCode = //Сообщает нам статус выполнения fooProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! System.out.println(fooPath + " -- fooProcess exitCode = " + exitCode); Thread.sleep(10_000); } } catch (последнее исключение исключения) { выдать новое RuntimeException (исключение); } окончательно { семафор.выпуск(); } } ) ; } частный процесс createzilklaquo (конечный путь fooPath) { пытаться { окончательный ProcessBuilder fooProcessBuilder = новый ProcessBuilder ( "коммд", "/С", "THIS_COMMAND_WILL_FAIL" ) .каталог ( корневая папка // .resolve(fooPath) // .тоФайл() // ) .inheritIO() ; fooProcessBuilder .среда() .put("SUB_FOLDER", fooPath.getFileName().toString()) ; окончательный процесс fooProcess = fooProcessBuilder .start() //Запускает вновь созданный процесс ; // Final int exitCode = //Сообщает нам статус выполнения // fooProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! // // System.out.println("fooProcess exitCode = " + exitCode); вернуть ФуПроцесс; } catch (последнее исключение e) { выдать новое RuntimeException(e); } } частный список getListOfbarfooPaths() выдает исключение { окончательный процесс fooListProcess = новый ProcessBuilder ( "cmd", //Поскольку это Windows, CMD — самый простой способ добиться того, что мы хотим "/C", //Запускает экземпляр CMD, выполняет приведенные ниже команды, выводит/передаёт их по конвейеру, а затем немедленно закрывает "dir", //Перечисляет все содержимое папки "/A:D", //фильтрует содержимое только по каталогам "/B" //Удаляет лишние метаданные — только имена ) .каталог ( rootbarFolder //Выполняем действие в корневой папке панели .toFile() //Хотелось бы указать путь вместо файла ) //.inheritIO() //Пересылаем все входные и выходные данные так же, как в Java (закомментировано, потому что это заглушает мои журналы) .start() //Запускает вновь созданный процесс ; Final int exitCode = //Сообщает нам статус выполнения fooListProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! System.out.println("fooListProcess exitCode = " + exitCode); Final String fooListRawOutput = //Необработанный вывод вновь созданного процесса новый Нить ( fooListProcess //Теперь, когда процесс завершился, мы можем извлечь из него данные .getInputStream() //Вызов OUTPUT процесса заключается в вызове getINPUTStream – очень неинтуитивно .readAllBytes() //Давайте все это сделаем ) ; Final List fooList = //Список foos, с которыми мы будем работать fooListRawOutput //Мы будем извлекать его из необработанного вывода .lines() //Это список, разделенный новой строкой, поэтому разбивается по строкам .map(rootbarFolder::resolve) //Превратим его в путь, который является корневой папкой, разрешенной в подпапку -- root -> root/subFolder .toList() //Наконец, помещаем содержимое в список ; fooList.forEach(System.out::println); вернуть fooList; } } Опять же, это фейковый пример, основанный на реальном, который я не могу показать из-за политики компании.
У меня есть папка со множеством подпапок. Например, я указываю на папку «Пользователи» на диске C:/ Windows. Если вы используете Linux или что-то еще, не стесняйтесь изменить эту переменную Path вверху, чтобы она указывала на другой каталог на вашем компьютере. Но пусть это будет каталог с несколькими элементами в этом каталоге.
Итак, вот папки на моем компьютере C:/Users.
C:\Users\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Но когда я запускаю эту программу, она выдает оператор печати только для C:\Users\All Users, а не для каких-либо других строк. Это означает, что эта программа не пытается использовать другие потоки.
Вот что он печатает.
$ java Main.java код выхода fooListProcess = 0 C:\Пользователи\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Попытка C:\Users\All Users «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\All Users -- fooProcess exitCode = 1 Итак, мы видим, что он попытался открыть папку «Все пользователи», но затем остановился.
Я ожидал чего-то большего.
java Main.java код выхода fooListProcess = 0 C:\Пользователи\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Попытка C:\Users\All Users «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\All Users -- fooProcess exitCode = 1 Попытка C:\Users\david «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\david -- fooProcess exitCode = 1 ...повторите для всех остальных папок Но в любом случае я хочу использовать многопоточность, чтобы поработать с этими подпапками. Работа, которую я делаю, часто терпит неудачу, поэтому у меня есть цикл while, который прослушивает код выхода и повторяет попытку. Однако по причинам, которые я не могу сказать, мне нужен аварийный люк, говорящий: «С этого момента любые будущие сбои должны прекращать выполнение потоков». Для этого и нужен JOptionPane. Я знаю, что это ужасный пример, но дело в том, что он переключает флаг boolean, а это именно то, что мне нужно.
Но вот в чем моя проблема. Когда я переключаю флаг, последующие потоки, которые должны ожидать, пока семафор освободит свободный слот, не запускаются.
Что касается того, что буквально делает приведенный выше код, он пытается выполнить команду, которая гарантированно завершится неудачей, запуская упомянутый мной механизм цикла while. Затем поток приостанавливается на 10 секунд и повторяет попытку.
У меня есть всплывающее окно, которое позволяет мне установить флаг, когда я выберу, нажав ОК. Когда я это делаю, первый поток завершается, но следующий никогда не запускается.
Теперь я знаю, что JVM может использовать «ярлыки» многопоточности (из-за отсутствия лучшего термина), и это, скорее всего, то, что здесь происходит. Но я не знаю, является ли это причиной.
Почему остальные мои темы не запускаются?
РЕДАКТИРОВАТЬ. Я заметил несколько закрытых голосов, утверждающих, что мой вопрос не имеет отношения к StackOverflow. К сожалению, это слишком широко, чтобы я мог понять, как улучшить свой вопрос.
Весь мой вопрос заключается в следующем: мне трудно понять, почему базовые библиотеки из стандартной библиотеки Java не делают то, что, по моему мнению, они должны делать. Я ясно излагаю свое понимание их, я показал свою попытку, и мой пример прост, минимален и воспроизводим (во всяком случае, насколько может судить мой компьютер). Если мне нужно что-то сделать или я что-то не сделал, сообщите мне об этом специально, чтобы я мог внести изменения.
РЕДАКТИРОВАТЬ 2. О, очевидно, если вы нажмете на закрытые голоса, а затем нажмете на выбор, они будут более подробно описаны. Не очень интуитивно понятно, но теперь я понимаю.
Я добавил всю запрошенную информацию. Как ни странно, это также подтолкнуло меня в правильном направлении, и я смог решить эту проблему сам. Не стесняйтесь опубликовать ответ, но решение оказалось до неприличия простым.
Насколько я понимаю, java.util.concurrent.Semaphore позволяет мне указать, сколько потоков могут использовать ресурс одновременно. Поток может использовать Semaphore.acquireUninterruptible() для использования ограниченного числа «слотов» в семафоре. После завершения потока необходимо выполнить вызов Semaphore.release(), чтобы вернуть слот, чтобы другой ожидающий поток (acquireUninterruptible()) заставляет поток ждать) может захватить новый слот. Я осведомлен о политике справедливости, и порядок тем не имеет значения для моих целей. Важно то, что все потоки выполняются.
И в этом моя проблема — выполняется только один из потоков. Вот мой код.
import java.nio.file.Path; импортировать java.util.ArrayList; импортировать java.util.List; импортировать java.util.concurrent.Semaphore; общественный класс Главный { частный статический окончательный путь rootbarFolder = Path.of("C:", "Users"); частное логическое значение REATTEMPT_UPON_FAILURE = true; public static void main(final String[] args) выдает исключение { новый Главный(); } частный Main() выдает исключение { javax.swing.SwingUtilities .invokeLater ( () -> { javax.swing.JOptionPane.showMessageDialog(null, «Закройте это всплывающее окно, чтобы программа завершила работу в случае сбоя»); this.REATTEMPT_UPON_FAILURE = ложь; } ) ; окончательный список fooPathList = this.getListOfbarfooPaths(); окончательный List fooPathThreads = новый ArrayList(); окончательный семафор семафора = новый семафор (1, правда); KICK_OFF_THREADS: for (конечный путь fooPath: fooPathList) { конечный поток fooPathThread = this.createThread(семафор, fooPath); fooPathThreads.add(fooPathThread); семафор.acquireUninterruptible(); fooPathThread.start(); } ПРИСОЕДИНЯЙТЕСЬ_THREADS: for (последняя тема fooPathThread: fooPathThreads) { fooPathThread.join(); } } частный поток createThread (последний семафор семафора, окончательный путь fooPath) { возвращаться Нить .ofPlatform() .unstarted ( () -> { пытаться { INT код выхода = -1; while (exitCode!= 0 && this.REATTEMPT_UPON_FAILURE) { System.out.println("\n\nПопытка " + fooPath); окончательный процесс fooProcess = this.createzilklaquo(fooPath); exitCode = //Сообщает нам статус выполнения fooProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! System.out.println(fooPath + " -- fooProcess exitCode = " + exitCode); Thread.sleep(10_000); } } catch (последнее исключение исключения) { выдать новое RuntimeException (исключение); } окончательно { семафор.выпуск(); } } ) ; } частный процесс createzilklaquo (конечный путь fooPath) { пытаться { окончательный ProcessBuilder fooProcessBuilder = новый ProcessBuilder ( "коммд", "/С", "THIS_COMMAND_WILL_FAIL" ) .каталог ( корневая папка // .resolve(fooPath) // .тоФайл() // ) .inheritIO() ; fooProcessBuilder .среда() .put("SUB_FOLDER", fooPath.getFileName().toString()) ; окончательный процесс fooProcess = fooProcessBuilder .start() //Запускает вновь созданный процесс ; // Final int exitCode = //Сообщает нам статус выполнения // fooProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! // // System.out.println("fooProcess exitCode = " + exitCode); вернуть ФуПроцесс; } catch (последнее исключение e) { выдать новое RuntimeException(e); } } частный список getListOfbarfooPaths() выдает исключение { окончательный процесс fooListProcess = новый ProcessBuilder ( "cmd", //Поскольку это Windows, CMD — самый простой способ добиться того, что мы хотим "/C", //Запускает экземпляр CMD, выполняет приведенные ниже команды, выводит/передаёт их по конвейеру, а затем немедленно закрывает "dir", //Перечисляет все содержимое папки "/A:D", //фильтрует содержимое только по каталогам "/B" //Удаляет лишние метаданные — только имена ) .каталог ( rootbarFolder //Выполняем действие в корневой папке панели .toFile() //Хотелось бы указать путь вместо файла ) //.inheritIO() //Пересылаем все входные и выходные данные так же, как в Java (закомментировано, потому что это заглушает мои журналы) .start() //Запускает вновь созданный процесс ; Final int exitCode = //Сообщает нам статус выполнения fooListProcess.waitFor(); //Не закрывайте JVM до завершения этого процесса! System.out.println("fooListProcess exitCode = " + exitCode); Final String fooListRawOutput = //Необработанный вывод вновь созданного процесса новый Нить ( fooListProcess //Теперь, когда процесс завершился, мы можем извлечь из него данные .getInputStream() //Вызов OUTPUT процесса заключается в вызове getINPUTStream – очень неинтуитивно .readAllBytes() //Давайте все это сделаем ) ; Final List fooList = //Список foos, с которыми мы будем работать fooListRawOutput //Мы будем извлекать его из необработанного вывода .lines() //Это список, разделенный новой строкой, поэтому разбивается по строкам .map(rootbarFolder::resolve) //Превратим его в путь, который является корневой папкой, разрешенной в подпапку -- root -> root/subFolder .toList() //Наконец, помещаем содержимое в список ; fooList.forEach(System.out::println); вернуть fooList; } } Опять же, это фейковый пример, основанный на реальном, который я не могу показать из-за политики компании.
У меня есть папка со множеством подпапок. Например, я указываю на папку «Пользователи» на диске C:/ Windows. Если вы используете Linux или что-то еще, не стесняйтесь изменить эту переменную Path вверху, чтобы она указывала на другой каталог на вашем компьютере. Но пусть это будет каталог с несколькими элементами в этом каталоге.
Итак, вот папки на моем компьютере C:/Users.
C:\Users\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Но когда я запускаю эту программу, она выдает оператор печати только для C:\Users\All Users, а не для каких-либо других строк. Это означает, что эта программа не пытается использовать другие потоки.
Вот что он печатает.
$ java Main.java код выхода fooListProcess = 0 C:\Пользователи\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Попытка C:\Users\All Users «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\All Users -- fooProcess exitCode = 1 Итак, мы видим, что он попытался открыть папку «Все пользователи», но затем остановился.
Я ожидал чего-то большего.
java Main.java код выхода fooListProcess = 0 C:\Пользователи\Все пользователи C:\Пользователи\Дэвид C:\Пользователи\По умолчанию C:\Пользователи\Пользователь по умолчанию C:\Пользователи\Публикация Попытка C:\Users\All Users «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\All Users -- fooProcess exitCode = 1 Попытка C:\Users\david «THIS_COMMAND_WILL_FAIL» не распознается как внутренняя или внешняя команда, действующая программа или командный файл. C:\Users\david -- fooProcess exitCode = 1 ...повторите для всех остальных папок Но в любом случае я хочу использовать многопоточность, чтобы поработать с этими подпапками. Работа, которую я делаю, часто терпит неудачу, поэтому у меня есть цикл while, который прослушивает код выхода и повторяет попытку. Однако по причинам, которые я не могу сказать, мне нужен аварийный люк, говорящий: «С этого момента любые будущие сбои должны прекращать выполнение потоков». Для этого и нужен JOptionPane. Я знаю, что это ужасный пример, но дело в том, что он переключает флаг boolean, а это именно то, что мне нужно.
Но вот в чем моя проблема. Когда я переключаю флаг, последующие потоки, которые должны ожидать, пока семафор освободит свободный слот, не запускаются.
Что касается того, что буквально делает приведенный выше код, он пытается выполнить команду, которая гарантированно завершится неудачей, запуская упомянутый мной механизм цикла while. Затем поток приостанавливается на 10 секунд и повторяет попытку.
У меня есть всплывающее окно, которое позволяет мне установить флаг, когда я выберу, нажав ОК. Когда я это делаю, первый поток завершается, но следующий никогда не запускается.
Теперь я знаю, что JVM может использовать «ярлыки» многопоточности (из-за отсутствия лучшего термина), и это, скорее всего, то, что здесь происходит. Но я не знаю, является ли это причиной.
Почему остальные мои темы не запускаются?
РЕДАКТИРОВАТЬ. Я заметил несколько закрытых голосов, утверждающих, что мой вопрос не имеет отношения к StackOverflow. К сожалению, это слишком широко, чтобы я мог понять, как улучшить свой вопрос.
Весь мой вопрос заключается в следующем: мне трудно понять, почему базовые библиотеки из стандартной библиотеки Java не делают то, что, по моему мнению, они должны делать. Я ясно излагаю свое понимание их, я показал свою попытку, и мой пример прост, минимален и воспроизводим (во всяком случае, насколько может судить мой компьютер). Если мне нужно что-то сделать или я что-то не сделал, сообщите мне об этом специально, чтобы я мог внести изменения.
РЕДАКТИРОВАТЬ 2. О, очевидно, если вы нажмете на закрытые голоса, а затем нажмете на выбор, они будут более подробно описаны. Не очень интуитивно понятно, но теперь я понимаю.
Я добавил всю запрошенную информацию. Как ни странно, это также подтолкнуло меня в правильном направлении, и я смог решить эту проблему сам. Не стесняйтесь опубликовать ответ, но решение оказалось до неприличия простым.
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Как использовать семафор вместо этого кода (ожидание с активным циклом) ядра Linux?
Anonymous » » в форуме Linux - 0 Ответы
- 15 Просмотры
-
Последнее сообщение Anonymous
-