gpt4 book ai didi

java - Thread.sleep 阻塞其他线程

转载 作者:行者123 更新时间:2023-12-02 03:05:01 25 4
gpt4 key购买 nike

我有一个输出类,它只打印它要打印的所有内容。

public class Output {
private static List<String> textList = new ArrayList<>();
private static Output output = null;

private Output() {
Runnable task = () -> {
int lastIndex = 0;

while (true) {
while (lastIndex < textList.size()) {
System.out.println(lastIndex + " - " + textList.size() + ": " + textList.get(lastIndex));

outputText(textList.get(lastIndex));

lastIndex ++;
}
}
};

new Thread(task).start();
}

private static void outputText(String text) {
synchronized (System.out) {
System.out.println(text);
}

}

public static void say(String text) {
if (output == null) {
output = new Output();
}

textList.add(text);
}
}

当我添加要打印的内容时,一切正常:

for (int i = 0; i < 10; i++) {
Output.say("" + i);
}

但是当我将 Thread.sleep 添加到循环中时,它会在第一个输出处停止:

for (int i = 0; i < 10; i++) {
Output.say("" + i);
Thread.sleep(100);
}

我该如何预防呢?我的意思是,我只是停止主线程的 sleep ,而不是单独的线程。

最佳答案

当您没有正确同步线程时,无法保证线程可以看到其他线程所做的更新。他们可能完全错过更新或只看到其中的一部分,从而产生完全不一致的结果。有时他们甚至可能看起来在做正确的事情。如果没有适当的同步(在指定为线程安全的任何有效构造的意义上),这是完全不可预测的。

有时,看到特定行为的机会会更高,就像您的示例一样。在大多数运行中,没有 sleep 的循环将在另一个线程开始工作之前完成,而插入 sleep增加第二个线程看到值后丢失更新的可能性。一旦第二个线程看到textList.size()的值,它可能会永远重用该值,评估 lastIndex < textList.size()false并执行相当于 while(true) { } .

有趣的是,您插入线程安全构造的唯一地方是方法 outputText仅由单个线程调用(无论如何,打印到 System.out 在大多数环境中都是内部同步的)。

此外,尚不清楚为什么要创建 Output 类型的对象这与这里无关,因为所有字段和方法都是 static .

您的代码可以更正并简化为

public static void main(String[] args) throws InterruptedException {
List<String> textList = new ArrayList<>();
new Thread( () -> {
int index=0;
while(true) synchronized(textList) {
for(; index<textList.size(); index++)
System.out.println(textList.get(index));
}
}).start();

for (int i = 0; i < 10; i++) {
synchronized(textList) {
textList.add(""+i);
}
Thread.sleep(100);
}
}

尽管它仍然包含原始代码由于无限的第二线程而永远不会终止的问题,并且还通过轮询循环烧毁CPU。您应该让第二个线程等待新项目并添加终止条件:

public static void main(String[] args) throws InterruptedException {
List<String> textList = new ArrayList<>();
new Thread( () -> {
synchronized(textList) {
for(int index=0; ; index++) {
while(index>=textList.size()) try {
textList.wait();
} catch(InterruptedException ex) { return; }
final String item = textList.get(index);
if(item==null) break;
System.out.println(item);
}
}
}).start();

for (int i = 0; i < 10; i++) {
synchronized(textList) {
textList.add(""+i);
textList.notify();
}
Thread.sleep(100);
}
synchronized(textList) {
textList.add(null);
textList.notify();
}
}

这仍然只是一个学术示例,您不应该在现实生活代码中使用。 Java API 提供了一些用于线程安全数据交换的类,消除了您自己实现此类事物的负担。

public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
String endMarker = "END-OF-QUEUE"; // the queue does not allow null
new Thread( () -> {
for(;;) try {
String item = queue.take();
if(item == endMarker) break;// don't use == for ordinary strings
System.out.println(item);
} catch(InterruptedException ex) { return; }
}).start();

for (int i = 0; i < 10; i++) {
queue.put(""+i);
Thread.sleep(100);
}
queue.put(endMarker);
}

关于java - Thread.sleep 阻塞其他线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41875062/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com