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

afdcj2ne  于 12个月前  发布在  Java
关注(0)|答案(1)|浏览(196)

**已关闭。**此问题需要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()使线程等待)可以抓住新的插槽。我知道公平策略,线程的顺序与我的目的无关。重要的是所有线程都执行。
这就是我的问题--只有一个线程执行。下面是我的代码。

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
 
public class Main
{
 
   private static final Path rootbarFolder = Path.of("C:", "Users");
 
   private boolean REATTEMPT_UPON_FAILURE = true;
 
   public static void main(final String[] args) throws Exception
   {
  
      new Main();
  
   }
 
   private Main() throws Exception
   {
  
      javax.swing.SwingUtilities
         .invokeLater
         (
            () ->
            {
           
               javax.swing.JOptionPane.showMessageDialog(null, "Close this popup window to make the program exit on failure");
           
               this.REATTEMPT_UPON_FAILURE = false;
           
            }
         )
         ;
  
      final List<Path> fooPathList = this.getListOfbarfooPaths();
  
      final List<Thread> fooPathThreads = new ArrayList<>();
  
      final Semaphore semaphore = new Semaphore(1, true);
  
      KICK_OFF_THREADS:
      for (final Path fooPath : fooPathList)
      {
     
         final Thread fooPathThread = this.createThread(semaphore, fooPath);
     
         fooPathThreads.add(fooPathThread);
     
         semaphore.acquireUninterruptibly();
     
         fooPathThread.start();
        
      }
  
      JOIN_THREADS:
      for (final Thread fooPathThread : fooPathThreads)
      {
     
         fooPathThread.join();
        
      }
  
   }
 
   private Thread createThread(final Semaphore semaphore, final Path fooPath)
   {
  
      return
         Thread
            .ofPlatform()
            .unstarted
            (
               () ->
               {
              
                  try
                  {
                 
                     int exitCode = -1;
                 
                     while (exitCode != 0 && this.REATTEMPT_UPON_FAILURE)
                     {
                    
                        System.out.println("\n\nAttempting " + fooPath);

                        final Process fooProcess = this.createzilklaquo(fooPath);
                    
                        exitCode =                             //Tells us the status of the run
                           fooProcess.waitFor();           //Don't close down the JVM before this process finishes running!
                    
                        System.out.println(fooPath + " -- fooProcess exitCode = " + exitCode);
                        Thread.sleep(10_000);
                    
                     }
                 
                  }
                 
                  catch (final Exception exception)
                  {
                 
                     throw new RuntimeException(exception);
                 
                  }
                 
                  finally
                  {
                 
                     semaphore.release();
                 
                  }
              
               }
            )
            ;
  
   }
 
   private Process createzilklaquo(final Path fooPath)
   {
  
      try
      {
     
         final ProcessBuilder fooProcessBuilder =
            new
               ProcessBuilder
               (
                  "cmd",
                  "/C",
                  "THIS_COMMAND_WILL_FAIL"
               )
               .directory
               (
                  rootbarFolder              //
                     .resolve(fooPath)      //
                     .toFile()                  //
               )
               .inheritIO()
               ;
     
         fooProcessBuilder
            .environment()
            .put("SUB_FOLDER", fooPath.getFileName().toString())
            ;
     
         final Process fooProcess =
            fooProcessBuilder
               .start()                            //Kicks off the newly created Process
               ;
     
         // final int exitCode =                   //Tells us the status of the run
            // fooProcess.waitFor();           //Don't close down the JVM before this process finishes running!
      //
         // System.out.println("fooProcess exitCode = " + exitCode);
     
         return fooProcess;
     
      }
     
      catch (final Exception e)
      {
     
         throw new RuntimeException(e);
     
      }
  
   }
 
   private List<Path> getListOfbarfooPaths() throws Exception
   {
  
      final Process fooListProcess =
         new
            ProcessBuilder
            (
               "cmd",                        //Since this is Windows, CMD is the easiest way to accomplish what we want
               "/C",                         //Starts an instance of CMD, does the below commands, outputs/pipes them, then immediately closes
               "dir",                        //Lists all contents in the folder
               "/A:D",                       //Filters the contents down to only directories
               "/B"                          //Removes extra metadata -- just the names
            )
            .directory
            (
               rootbarFolder              //Perform the action in the root bar folder
                  .toFile()                  //Wish I could give a Path instead of a File
            )
            //.inheritIO()                     //Forward all Input and Output to the same as Java's (commented out because it drowns out my logs)
            .start()                         //Kicks off the newly created Process
            ;
  
      final int exitCode =                   //Tells us the status of the run
         fooListProcess.waitFor();       //Don't close down the JVM before this process finishes running!
  
      System.out.println("fooListProcess exitCode = " + exitCode);
  
      final String fooListRawOutput =    //The raw output from the newly created process
         new
            String
            (
               fooListProcess            //Now that the process has finished, we can pull from it
                  .getInputStream()          //The way that you quo the OUTPUT of the process is to call getINPUTStream -- very unintuitive
                  .readAllBytes()            //Let's quo all of it
            )
            ;
  
      final List<Path> fooList =       //The list of foos that we will be working with
         fooListRawOutput                //We will be extracting it from the raw output
            .lines()                         //It's a new-line-separated list, so split by line
            .map(rootbarFolder::resolve)  //Turn it into a Path that is the rootbarFolder resolved to the sub-folder -- root -> root/subFolder
            .toList()                        //Finally, put the contents into a list
            ;
  
      fooList.forEach(System.out::println);
  
      return fooList;
  
   }
 
}

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

C:\Users\All Users
C:\Users\david
C:\Users\Default
C:\Users\Default User
C:\Users\Public


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

$ java Main.java
fooListProcess exitCode = 0
C:\Users\All Users
C:\Users\david
C:\Users\Default
C:\Users\Default User
C:\Users\Public
Attempting C:\Users\All Users
'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\All Users -- fooProcess exitCode = 1


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

java Main.java
fooListProcess exitCode = 0
C:\Users\All Users
C:\Users\david
C:\Users\Default
C:\Users\Default User
C:\Users\Public
Attempting C:\Users\All Users
'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\All Users -- fooProcess exitCode = 1
Attempting C:\Users\david
'THIS_COMMAND_WILL_FAIL' is not recognized as an internal or external command,
operable program or batch file.
C:\Users\david -- fooProcess exitCode = 1

...repeat for all other folders


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

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

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

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

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

nimxete2

nimxete21#

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

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

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

相关问题