为什么我的线程在 Java 时突然停止?
Why are my threads suddenly stopping in Java?
我应该使用两个自定义信号量 类(二进制和计数)以精确的顺序打印字母。这是标准信号量。
public class Semaphore {
protected int value;
public Semaphore() {
value = 0;
}
public Semaphore(int initial) {
value = (initial >=0) ? initial : 0;
}
public synchronized void P() throws InterruptedException {
while (value==0) {
wait();
}
value--;
}
public synchronized void V() {
value++;
notify();
}
}
这是二进制信号量:
public class BinarySemaphore extends Semaphore {
public BinarySemaphore(boolean unlocked) {super(unlocked ? 1 : 0);}
public synchronized void P() throws InterruptedException{
while(value==0) {
wait();
}
value=0;
}
public synchronized void V() {
value=1;
notify();
}
}
这是代码的主要部分,除了我无法理解为什么线程在大约三十次重复后停止的原因。 Wait 没有被调用,真实的标准已经达到,那么他们为什么不工作呢?非常感谢任何帮助。
BinarySemaphore binaryWXSemaphore = new BinarySemaphore(false);
BinarySemaphore binaryYZSemaphore = new BinarySemaphore(false);
Semaphore countingWSemaphore = new Semaphore();
Semaphore countingYZSemaphore = new Semaphore();
Runnable runnableW = () -> {
while(true) {
if (binaryWXSemaphore.value == 0 && countingYZSemaphore.value >= countingWSemaphore.value) {
binaryWXSemaphore.V();
countingWSemaphore.V();
System.out.println("W");
}
}
};
Runnable runnableX = () -> {
while(true) {
if (binaryWXSemaphore.value == 1) {
try {
binaryWXSemaphore.P();
System.out.println("X");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
Runnable runnableY = () -> {
while(true) {
if (binaryYZSemaphore.value == 0 && countingWSemaphore.value > countingYZSemaphore.value) {
binaryYZSemaphore.V();
countingYZSemaphore.V();
System.out.println("y");
}
}
};
Runnable runnableZ = () -> {
while(true) {
if (binaryYZSemaphore.value == 1 && countingWSemaphore.value > countingYZSemaphore.value) {
try {
binaryYZSemaphore.P();
countingYZSemaphore.V();
System.out.println("z");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
正如@iggy 所指出的,这个问题与不同线程正在读取 value
的不同值这一事实有关,因为您访问它的方式不是线程安全的。某些线程可能正在使用该值的旧副本。使其易变意味着每个线程访问读取更一致的值:
protected volatile int value;
或切换到 AtomicInteger
,这确保线程对存储在 value
中的 int 进行一致更改。您还需要使用 AtomicInteger
:
的 set/get/inc/decrement 方法替换作业
protected final AtomicInteger value = new AtomicInteger();
// Then use value.set(0 / 1)
// or value.incrementAndGet / decrementAndGet
不幸的是,即使进行了上述更改,您可能会发现其他问题,因为 value
可能会改变每个 Runnable 的 if 语句之间的持续时间,以及那些 if
分支内的操作。
此外:将 notify()
替换为 notifyAll()
通常会提供更好的多线程处理,但我认为这不一定对您的示例有帮助。
我应该使用两个自定义信号量 类(二进制和计数)以精确的顺序打印字母。这是标准信号量。
public class Semaphore {
protected int value;
public Semaphore() {
value = 0;
}
public Semaphore(int initial) {
value = (initial >=0) ? initial : 0;
}
public synchronized void P() throws InterruptedException {
while (value==0) {
wait();
}
value--;
}
public synchronized void V() {
value++;
notify();
}
}
这是二进制信号量:
public class BinarySemaphore extends Semaphore {
public BinarySemaphore(boolean unlocked) {super(unlocked ? 1 : 0);}
public synchronized void P() throws InterruptedException{
while(value==0) {
wait();
}
value=0;
}
public synchronized void V() {
value=1;
notify();
}
}
这是代码的主要部分,除了我无法理解为什么线程在大约三十次重复后停止的原因。 Wait 没有被调用,真实的标准已经达到,那么他们为什么不工作呢?非常感谢任何帮助。
BinarySemaphore binaryWXSemaphore = new BinarySemaphore(false);
BinarySemaphore binaryYZSemaphore = new BinarySemaphore(false);
Semaphore countingWSemaphore = new Semaphore();
Semaphore countingYZSemaphore = new Semaphore();
Runnable runnableW = () -> {
while(true) {
if (binaryWXSemaphore.value == 0 && countingYZSemaphore.value >= countingWSemaphore.value) {
binaryWXSemaphore.V();
countingWSemaphore.V();
System.out.println("W");
}
}
};
Runnable runnableX = () -> {
while(true) {
if (binaryWXSemaphore.value == 1) {
try {
binaryWXSemaphore.P();
System.out.println("X");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
Runnable runnableY = () -> {
while(true) {
if (binaryYZSemaphore.value == 0 && countingWSemaphore.value > countingYZSemaphore.value) {
binaryYZSemaphore.V();
countingYZSemaphore.V();
System.out.println("y");
}
}
};
Runnable runnableZ = () -> {
while(true) {
if (binaryYZSemaphore.value == 1 && countingWSemaphore.value > countingYZSemaphore.value) {
try {
binaryYZSemaphore.P();
countingYZSemaphore.V();
System.out.println("z");
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
正如@iggy 所指出的,这个问题与不同线程正在读取 value
的不同值这一事实有关,因为您访问它的方式不是线程安全的。某些线程可能正在使用该值的旧副本。使其易变意味着每个线程访问读取更一致的值:
protected volatile int value;
或切换到 AtomicInteger
,这确保线程对存储在 value
中的 int 进行一致更改。您还需要使用 AtomicInteger
:
protected final AtomicInteger value = new AtomicInteger();
// Then use value.set(0 / 1)
// or value.incrementAndGet / decrementAndGet
不幸的是,即使进行了上述更改,您可能会发现其他问题,因为 value
可能会改变每个 Runnable 的 if 语句之间的持续时间,以及那些 if
分支内的操作。
此外:将 notify()
替换为 notifyAll()
通常会提供更好的多线程处理,但我认为这不一定对您的示例有帮助。