java 当尝试使用信号量时,只有一个线程执行[关闭]

afdcj2ne  于 2024-01-05  发布在  Java
关注(0)|答案(1)|浏览(238)

**已关闭。**此问题需要debugging details。目前不接受回答。

编辑问题以包括desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答问题。
4天前关闭。
社区在4天前审查了是否重新打开此问题,并将其关闭:

不适合本网站此问题是由错别字或无法再复制的问题引起的。虽然类似的问题可能是on-topic在这里,但这一个问题的解决方式不太可能帮助未来的读者。

Improve this question
根据我的理解,java.util.concurrent.Semaphore允许我指定一次可以有多少个线程使用一个资源。一个线程可以使用Semaphore.acquireUninterruptibly()来消耗信号量中有限数量的“插槽”。一旦线程完成,应该调用Semaphore.release()以给予插槽,以便另一个正在等待的线程(acquireUninterruptibly()使线程等待)可以抓住新的插槽。我知道公平策略,线程的顺序与我的目的无关。重要的是所有线程都执行。
这就是我的问题--只有一个线程执行。下面是我的代码。

  1. import java.nio.file.Path;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import java.util.concurrent.Semaphore;
  5. public class Main
  6. {
  7. private static final Path rootbarFolder = Path.of("C:", "Users");
  8. private boolean REATTEMPT_UPON_FAILURE = true;
  9. public static void main(final String[] args) throws Exception
  10. {
  11. new Main();
  12. }
  13. private Main() throws Exception
  14. {
  15. javax.swing.SwingUtilities
  16. .invokeLater
  17. (
  18. () ->
  19. {
  20. javax.swing.JOptionPane.showMessageDialog(null, "Close this popup window to make the program exit on failure");
  21. this.REATTEMPT_UPON_FAILURE = false;
  22. }
  23. )
  24. ;
  25. final List<Path> fooPathList = this.getListOfbarfooPaths();
  26. final List<Thread> fooPathThreads = new ArrayList<>();
  27. final Semaphore semaphore = new Semaphore(1, true);
  28. KICK_OFF_THREADS:
  29. for (final Path fooPath : fooPathList)
  30. {
  31. final Thread fooPathThread = this.createThread(semaphore, fooPath);
  32. fooPathThreads.add(fooPathThread);
  33. semaphore.acquireUninterruptibly();
  34. fooPathThread.start();
  35. }
  36. JOIN_THREADS:
  37. for (final Thread fooPathThread : fooPathThreads)
  38. {
  39. fooPathThread.join();
  40. }
  41. }
  42. private Thread createThread(final Semaphore semaphore, final Path fooPath)
  43. {
  44. return
  45. Thread
  46. .ofPlatform()
  47. .unstarted
  48. (
  49. () ->
  50. {
  51. try
  52. {
  53. int exitCode = -1;
  54. while (exitCode != 0 && this.REATTEMPT_UPON_FAILURE)
  55. {
  56. System.out.println("\n\nAttempting " + fooPath);
  57. final Process fooProcess = this.createzilklaquo(fooPath);
  58. exitCode = //Tells us the status of the run
  59. fooProcess.waitFor(); //Don't close down the JVM before this process finishes running!
  60. System.out.println(fooPath + " -- fooProcess exitCode = " + exitCode);
  61. Thread.sleep(10_000);
  62. }
  63. }
  64. catch (final Exception exception)
  65. {
  66. throw new RuntimeException(exception);
  67. }
  68. finally
  69. {
  70. semaphore.release();
  71. }
  72. }
  73. )
  74. ;
  75. }
  76. private Process createzilklaquo(final Path fooPath)
  77. {
  78. try
  79. {
  80. final ProcessBuilder fooProcessBuilder =
  81. new
  82. ProcessBuilder
  83. (
  84. "cmd",
  85. "/C",
  86. "THIS_COMMAND_WILL_FAIL"
  87. )
  88. .directory
  89. (
  90. rootbarFolder //
  91. .resolve(fooPath) //
  92. .toFile() //
  93. )
  94. .inheritIO()
  95. ;
  96. fooProcessBuilder
  97. .environment()
  98. .put("SUB_FOLDER", fooPath.getFileName().toString())
  99. ;
  100. final Process fooProcess =
  101. fooProcessBuilder
  102. .start() //Kicks off the newly created Process
  103. ;
  104. // final int exitCode = //Tells us the status of the run
  105. // fooProcess.waitFor(); //Don't close down the JVM before this process finishes running!
  106. //
  107. // System.out.println("fooProcess exitCode = " + exitCode);
  108. return fooProcess;
  109. }
  110. catch (final Exception e)
  111. {
  112. throw new RuntimeException(e);
  113. }
  114. }
  115. private List<Path> getListOfbarfooPaths() throws Exception
  116. {
  117. final Process fooListProcess =
  118. new
  119. ProcessBuilder
  120. (
  121. "cmd", //Since this is Windows, CMD is the easiest way to accomplish what we want
  122. "/C", //Starts an instance of CMD, does the below commands, outputs/pipes them, then immediately closes
  123. "dir", //Lists all contents in the folder
  124. "/A:D", //Filters the contents down to only directories
  125. "/B" //Removes extra metadata -- just the names
  126. )
  127. .directory
  128. (
  129. rootbarFolder //Perform the action in the root bar folder
  130. .toFile() //Wish I could give a Path instead of a File
  131. )
  132. //.inheritIO() //Forward all Input and Output to the same as Java's (commented out because it drowns out my logs)
  133. .start() //Kicks off the newly created Process
  134. ;
  135. final int exitCode = //Tells us the status of the run
  136. fooListProcess.waitFor(); //Don't close down the JVM before this process finishes running!
  137. System.out.println("fooListProcess exitCode = " + exitCode);
  138. final String fooListRawOutput = //The raw output from the newly created process
  139. new
  140. String
  141. (
  142. fooListProcess //Now that the process has finished, we can pull from it
  143. .getInputStream() //The way that you quo the OUTPUT of the process is to call getINPUTStream -- very unintuitive
  144. .readAllBytes() //Let's quo all of it
  145. )
  146. ;
  147. final List<Path> fooList = //The list of foos that we will be working with
  148. fooListRawOutput //We will be extracting it from the raw output
  149. .lines() //It's a new-line-separated list, so split by line
  150. .map(rootbarFolder::resolve) //Turn it into a Path that is the rootbarFolder resolved to the sub-folder -- root -> root/subFolder
  151. .toList() //Finally, put the contents into a list
  152. ;
  153. fooList.forEach(System.out::println);
  154. return fooList;
  155. }
  156. }

字符串
同样,这是一个假的例子,基于一个真实的例子,我不能显示,因为公司的政策。
我有一个文件夹,里面有很多文件夹。举个例子,我把它指向Windows C:/驱动器中的Users文件夹。如果你是Linux或其他系统,可以随意更改顶部的Path变量,使其指向机器上的其他目录。但要让它成为一个目录,该目录中有多个项目。
所以,在我的机器上,这里是我的C:/Users文件夹中的文件夹。

  1. C:\Users\All Users
  2. C:\Users\david
  3. C:\Users\Default
  4. C:\Users\Default User
  5. C:\Users\Public


但是当我运行这个程序时,它只会为C:\Users\All Users生成一个print语句,而不会为其他行生成一个print语句,这意味着这个程序没有尝试其他线程。
这就是它打印的内容。

  1. $ java Main.java
  2. fooListProcess exitCode = 0
  3. C:\Users\All Users
  4. C:\Users\david
  5. C:\Users\Default
  6. C:\Users\Default User
  7. C:\Users\Public
  8. Attempting C:\Users\All Users
  9. 'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
  10. operable program or batch file.
  11. C:\Users\All Users -- fooProcess exitCode = 1


因此,我们可以看到它尝试了所有用户文件夹,但随后它就停止了。
我以为会是这样的。

  1. java Main.java
  2. fooListProcess exitCode = 0
  3. C:\Users\All Users
  4. C:\Users\david
  5. C:\Users\Default
  6. C:\Users\Default User
  7. C:\Users\Public
  8. Attempting C:\Users\All Users
  9. 'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
  10. operable program or batch file.
  11. C:\Users\All Users -- fooProcess exitCode = 1
  12. Attempting C:\Users\david
  13. 'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
  14. operable program or batch file.
  15. C:\Users\david -- fooProcess exitCode = 1
  16. ...repeat for all other folders


但是,无论如何,我想做多线程来做一些关于这些线程的工作。我正在做的工作经常失败,所以我有一个while循环来监听exitCode,然后重试。然而,由于我不能说的原因,我需要有一个逃生舱口,它说“从现在开始,任何未来的失败都应该结束线程的执行”。这就是JOptionPane的作用。我知道这是一个糟糕的例子,但重点是它切换了一个boolean标志,这就是我需要它做的。
但我的问题是,当我切换标志时,应该在信号量上等待空闲插槽的后续线程没有被踢出。
至于上面的代码实际上在做什么,它尝试了一个肯定会失败的命令,触发了我提到的while循环机制。然后,线程休眠10秒,然后再试一次。
我有一个弹出窗口,允许我设置标志时,我选择按确定。当我这样做,第一个线程完成,但下一个线程永远不会开始。
现在,我知道JVM可以采用多线程“捷径”(因为没有更好的术语),这很可能就是这里发生的事情,但我不知道这是否是原因。
为什么我的其他线程没有被踢掉?

编辑-我注意到一些接近的投票,声称我的问题与StackOverflow无关。不幸的是,这太宽泛了,我不知道如何改进我的问题。

我的整个问题是--我很难理解为什么Java标准库中的基本库没有做我认为它们应该做的事情。我清楚地传达了我对它们的理解,我展示了我的尝试,我的示例简单,最小化,可重复(就我的电脑可以告诉,无论如何)。如果有什么进一步的我应该做的,或者我没有做什么,请让我知 prop 体,以便我可以作出改变。

编辑2-哦,显然,如果你点击关闭的投票,然后点击选择,他们会进入更详细.不是很直观,但我现在明白了.

我已经添加了所有要求的信息。令人尴尬的是,这也给了我一个正确的方向,我能够自己解决它。随时发布答案,但解决方案非常简单。

nimxete2

nimxete21#

我真傻,看看那个while的条件。

  1. while (exitCode != 0 && this.REATTEMPT_UPON_FAILURE)

字符串
&&
这意味着一旦我们将标志设置为false,就没有其他东西会进入while循环。一个潜在的解决方案是do-while循环。

相关问题