无限期地停止 运行 的线程
stopping threads that run indefinitely
我一直在尝试实现生产者消费者模式。如果生产者和消费者都 运行 无限期地应该如何阻止他们?
我一直在尝试测试isInterrupted()
的状态,但是下面的代码并不能保证所有线程都停止。
public class Monitor {
private int value;
private boolean readable = false;
public synchronized void setVal(int value) {
while (readable) {
try {
this.wait();
} catch (InterruptedException e) {
break;
}
}
if (!Thread.currentThread().isInterrupted()) {
this.readable = true;
this.value = value;
this.notifyAll();
}
}
public synchronized int getVal() {
while (!readable) {
try {
this.wait();
} catch (InterruptedException e) {
break;
}
}
if (!Thread.currentThread().isInterrupted()) {
this.readable = false;
this.notifyAll();
}
return this.value;
}
}
制作人class长这样:
import java.util.Random;
public class Producer implements Runnable {
private Monitor monitor;
private Random r = new Random();
private String name;
public Producer(Monitor m) {monitor = m;}
public void run() {
name = Thread.currentThread().getName();
while (!Thread.currentThread().isInterrupted()) {
int value = r.nextInt(1000);
monitor.setVal(value);
System.out.println("PRODUCER: " + name + " set " + value);
}
System.out.println("PRODUCER: " + name + " interrupted");
}
}
消费者
public class Consumer implements Runnable {
private Monitor monitor;
private String name;
public Consumer(Monitor m) {monitor = m;}
public void run() {
name = Thread.currentThread().getName();
while (!Thread.currentThread().isInterrupted()) {
int value = monitor.getVal();
System.out.println("CONSUMER: " + name + " got " + value);
}
System.out.println("CONSUMER: " + name + " interrupted");
}
}
主要的:
public class Main {
public static void main(String[] args) {
final int n = 2;
Monitor m = new Monitor();
Thread[] producers = new Thread[n];
Thread[] consumers = new Thread[n];
for (int i = 0; i < n; i++) {
producers[i] = new Thread(new Producer(m));
producers[i].start();
consumers[i] = new Thread(new Consumer(m));
consumers[i].start();
}
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {}
for (int i = 0; i < n; i++) {
producers[i].interrupt();
consumers[i].interrupt();
}
}
}
我得到以下结果
PRODUCER: Thread-0 set 917
CONSUMER: Thread-1 got 917
PRODUCER: Thread-2 set 901
PRODUCER: Thread-0 set 29
CONSUMER: Thread-3 interrupted
CONSUMER: Thread-1 got 29
CONSUMER: Thread-1 interrupted
PRODUCER: Thread-2 set 825
...program hangs
和
PRODUCER: Thread-0 set 663
CONSUMER: Thread-1 got 663
PRODUCER: Thread-0 set 129
CONSUMER: Thread-1 got 129
PRODUCER: Thread-2 set 93
PRODUCER: Thread-2 interrupterd
CONSUMER: Thread-3 interrupted
PRODUCER: Thread-0 set 189
PRODUCER: Thread-0 interrupterd
CONSUMER: Thread-1 got 129
...program hangs
等...
明显有问题。为什么我没有在一致的基础上注册 interrupt
呼叫?
捕获 InterruptedException
并不 意味着在线程上设置了中断标志可能令人惊讶。
中断标志和InterruptedException
是两种完全不同的指示中断发生的方式:
- 您可以抛出
InterruptedException
而无需首先检查线程是否已被中断。
- 您可以在不捕获
InterruptedException
的情况下设置中断标志。
为了正确保留线程被中断的事实(或者,至少,一个 InterruptedException
被捕获),你应该在你的 catch 块中显式地重新中断线程:
// ...
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// ...
这会设置中断标志,因此您的 isInterrupted()
检查现在应该可以工作了。
我一直在尝试实现生产者消费者模式。如果生产者和消费者都 运行 无限期地应该如何阻止他们?
我一直在尝试测试isInterrupted()
的状态,但是下面的代码并不能保证所有线程都停止。
public class Monitor {
private int value;
private boolean readable = false;
public synchronized void setVal(int value) {
while (readable) {
try {
this.wait();
} catch (InterruptedException e) {
break;
}
}
if (!Thread.currentThread().isInterrupted()) {
this.readable = true;
this.value = value;
this.notifyAll();
}
}
public synchronized int getVal() {
while (!readable) {
try {
this.wait();
} catch (InterruptedException e) {
break;
}
}
if (!Thread.currentThread().isInterrupted()) {
this.readable = false;
this.notifyAll();
}
return this.value;
}
}
制作人class长这样:
import java.util.Random;
public class Producer implements Runnable {
private Monitor monitor;
private Random r = new Random();
private String name;
public Producer(Monitor m) {monitor = m;}
public void run() {
name = Thread.currentThread().getName();
while (!Thread.currentThread().isInterrupted()) {
int value = r.nextInt(1000);
monitor.setVal(value);
System.out.println("PRODUCER: " + name + " set " + value);
}
System.out.println("PRODUCER: " + name + " interrupted");
}
}
消费者
public class Consumer implements Runnable {
private Monitor monitor;
private String name;
public Consumer(Monitor m) {monitor = m;}
public void run() {
name = Thread.currentThread().getName();
while (!Thread.currentThread().isInterrupted()) {
int value = monitor.getVal();
System.out.println("CONSUMER: " + name + " got " + value);
}
System.out.println("CONSUMER: " + name + " interrupted");
}
}
主要的:
public class Main {
public static void main(String[] args) {
final int n = 2;
Monitor m = new Monitor();
Thread[] producers = new Thread[n];
Thread[] consumers = new Thread[n];
for (int i = 0; i < n; i++) {
producers[i] = new Thread(new Producer(m));
producers[i].start();
consumers[i] = new Thread(new Consumer(m));
consumers[i].start();
}
// try {
// Thread.sleep(1);
// } catch (InterruptedException e) {}
for (int i = 0; i < n; i++) {
producers[i].interrupt();
consumers[i].interrupt();
}
}
}
我得到以下结果
PRODUCER: Thread-0 set 917
CONSUMER: Thread-1 got 917
PRODUCER: Thread-2 set 901
PRODUCER: Thread-0 set 29
CONSUMER: Thread-3 interrupted
CONSUMER: Thread-1 got 29
CONSUMER: Thread-1 interrupted
PRODUCER: Thread-2 set 825
...program hangs
和
PRODUCER: Thread-0 set 663
CONSUMER: Thread-1 got 663
PRODUCER: Thread-0 set 129
CONSUMER: Thread-1 got 129
PRODUCER: Thread-2 set 93
PRODUCER: Thread-2 interrupterd
CONSUMER: Thread-3 interrupted
PRODUCER: Thread-0 set 189
PRODUCER: Thread-0 interrupterd
CONSUMER: Thread-1 got 129
...program hangs
等...
明显有问题。为什么我没有在一致的基础上注册 interrupt
呼叫?
捕获 InterruptedException
并不 意味着在线程上设置了中断标志可能令人惊讶。
中断标志和InterruptedException
是两种完全不同的指示中断发生的方式:
- 您可以抛出
InterruptedException
而无需首先检查线程是否已被中断。 - 您可以在不捕获
InterruptedException
的情况下设置中断标志。
为了正确保留线程被中断的事实(或者,至少,一个 InterruptedException
被捕获),你应该在你的 catch 块中显式地重新中断线程:
// ...
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// ...
这会设置中断标志,因此您的 isInterrupted()
检查现在应该可以工作了。