**已关闭。**此问题需要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-哦,显然,如果你点击关闭的投票,然后点击选择,他们会进入更详细.不是很直观,但我现在明白了.
我已经添加了所有要求的信息。令人尴尬的是,这也给了我一个正确的方向,我能够自己解决它。随时发布答案,但解决方案非常简单。
1条答案
按热度按时间nimxete21#
我真傻,看看那个
while
的条件。字符串
&&
这意味着一旦我们将标志设置为false,就没有其他东西会进入while循环。一个潜在的解决方案是do-while循环。