gpt4 book ai didi

Java多线程在同一个 block 中等待和通知

转载 作者:搜寻专家 更新时间:2023-11-01 02:56:47 27 4
gpt4 key购买 nike

我正在处理一个小问题,我需要用两个线程以交替方式顺序打印数字。就像线程 1 打印 1,线程 2 打印 2,线程 1 打印 3 等等......

所以我创建了下面的一段代码,但在某些时候两个线程都进入等待状态并且控制台上没有任何打印。

import java.util.concurrent.atomic.AtomicInteger;

public class MultiPrintSequence {

public static void main(String[] args) {
AtomicInteger integer=new AtomicInteger(0);
Sequence sequence1=new Sequence(integer);
Sequence sequence2=new Sequence(integer);
sequence1.start();
sequence2.start();
}
}

class Sequence extends Thread{

private AtomicInteger integer;
boolean flag=false;

public Sequence(AtomicInteger integer) {
this.integer=integer;
}

@Override
public void run() {
while(true) {
synchronized (integer) {
while (flag) {
flag=false;
try {
System.out.println(Thread.currentThread().getName()+" waiting");
integer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+integer.incrementAndGet());
flag = true;
System.out.println(Thread.currentThread().getName()+" notifying");
integer.notify();
}
}
}
}

当观察控制台输出时,我注意到在某个时刻,当一个线程发出通知时,另一个线程最终甚至在通知线程进入等待状态之前就开始了,因此在某一时刻两个线程都进入了等待状态。以下是控制台输出的一小部分。

Thread-1 510
Thread-1 notifying
Thread-1 waiting
Thread-0 511
Thread-0 notifying
Thread-0 waiting
Thread-1 512
Thread-1 notifying
Thread-1 waiting
**Thread-0 513
Thread-0 notifying
Thread-1 514
Thread-1 notifying
Thread-1 waiting
Thread-0 waiting**

最佳答案

考虑一下这一系列不幸的事件。 Thread1 递增该值,将标志设置为 true 并通知等待集中的所有线程获取锁。现在 Thread0 已经在等待集中了。然后 Thread0 醒来,它的标志 = false。然后 Thread0 退出 while 循环并打印增加的值并通知所有等待的线程。然后它继续进行 while 循环中的下一次迭代并调用锁对象上的等待。但是 Thread1 并没有处于等待状态,而是在完成同步块(synchronized block)后被调度程序切换出 CPU,给 Thread0 一个机会。 Thread1 处于可运行状态,并且由于没有剩余可运行线程,调度程序再次给它机会。然后 Tread1 进入 while 循环,因为 flag = true,并在同一个锁对象上调用等待。现在两个线程都处于等待状态,没有人可以唤醒它们。所以这是系统中活锁的一个很好的例子。

发生这种情况是因为标志是一个实例字段,因此不会在线程之间共享。所以每个线程都有自己的标志副本。如果将其标记为静态变量,则两个线程共享该值,因此问题得到解决。标志声明应如下所示。

static boolean flag = false;

这如何解决问题?好吧,考虑相同的事件顺序。现在 Thread1 在调用锁定对象上的通知之前将标志值设置为 true。 Thread0 已经处于等待状态。调度程序将 Thread1 关闭 CPU,并为 Thread0 提供机会。它开始运行并且由于标志 = true,它进入 while 循环将标志设置为 false 并调用锁定对象上的等待。然后 Thread0 进入等待状态,调度给 Thread1 一个机会。 Thread1 恢复执行并且 flag = false,因此它退出 while 循环,打印增加的值并通知等待线程。所以现在没有活锁。

但是我看不出同时使用synchronized 和非阻塞原子变量有什么意义。你不应该同时使用它们。下面给出了一个更好、更高效的实现。

public class Sequence extends Thread {
private static final Object lock = new Object();
private static int integer = 0;
static boolean flag = false;

@Override
public void run() {
while (true) {
synchronized (lock) {
while (flag) {
flag = false;
try {
System.out.println(Thread.currentThread().getName() + " waiting");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " " + ++integer);
flag = true;
System.out.println(Thread.currentThread().getName() + " notifying");
lock.notify();
}
}
}

public static void main(String[] args) {
Sequence sequence1=new Sequence();
Sequence sequence2=new Sequence();
sequence1.start();
sequence2.start();
}
}

关于Java多线程在同一个 block 中等待和通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56292158/

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