Thread.sleep 显然不强制上下文切换
Thread.sleep doesn't force context switch apparently
主线程创建 child 线程。 Parent 需要 child 的一些工作,但不是全部,因此 parent 必须等到 child 完成该工作(child 将继续做其他工作).
我想用监视器来实现它,所以我编写了以下代码:
public class WaitChildThreadMonitor {
public static final int TOTAL_COUNT_AMOUNT = 1_000;
static int count = 0;
class Child implements Runnable {
@Override
public void run() {
work();
}
public synchronized void work() {
letParentWaitForThis();
for (int i = 0; i < TOTAL_COUNT_AMOUNT; i++)
++WaitChildThreadMonitor.count;
this.notifyAll();
// More child work that parent doesn't need right now
// ...
for (int i = 0; i < TOTAL_COUNT_AMOUNT; i++)
++WaitChildThreadMonitor.count;
}
private void letParentWaitForThis() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
public synchronized void waitForWork() throws InterruptedException {
this.wait();
}
}
void main() throws InterruptedException {
Child child = new Child();
Thread childThread = new Thread(child);
// If the next two methods doesn't execute atomically,
// parent execution gets blocked forever
childThread.start();
child.waitForWork();
System.out.printf("Count value is %d\n", WaitChildThreadMonitor.count);
childThread.join();
}
public static void main(String[] args) throws InterruptedException {
(new WaitChildThreadMonitor()).main();
}
}
问题是,如果child在parent完成主要工作后执行"this.notifyAll()",然后"child.waitForWork()"执行"this.wait()",parent 不会收到通知,将永远被阻止。
我试图解决这个问题,在 child 使用 Thread.sleep() 方法开始他的工作之前强制进行上下文切换。它似乎没有按预期工作。
睡眠和不睡眠,有时 parent 会被阻塞,程序永远不会结束,有时它会正确结束(我猜是因为 parent 在 child 通知之前等待)。
我该如何解决这个问题?
提前致谢!
如果你想等待的事情已经发生,你就不能打电话给wait
。这就是调用 wait
的方法是 synchronized
的原因——因此您可以检查代表您正在等待的东西的共享状态。
所以这是一个标准的 producer-consumer 问题。很久以前,我写了一个只使用 synchronized
和 wait-notify
的实现。我看不到您的代码产生了什么;此代码仅使用 int 作为生成的内容。将 Storage
中的数组类型更改为其他 class 类型。
package quicktest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
*
* @author Brenden Towey
*/
public class ProducerConsumer {
public static void main(String[] args) throws InterruptedException {
Storage circularBuffer = new Storage();
Counter producer1 = new Counter( circularBuffer, 1000 );
Counter producer2 = new Counter( circularBuffer, 2000 );
Counter producer3 = new Counter( circularBuffer, 3000 );
Counter producer4 = new Counter( circularBuffer, 4000 );
ExecutorService exe = Executors.newCachedThreadPool();
exe.execute( producer1 );
exe.execute( producer2 );
exe.execute( producer3 );
exe.execute( producer4 );
Printer consumer = new Printer( circularBuffer );
exe.execute( consumer );
Thread.sleep( 100 );// wait a bit
exe.shutdownNow();
exe.awaitTermination( 10, TimeUnit.SECONDS );
}
}
// Producer
class Counter implements Runnable {
private final Storage output;
private final int startingValue;
public Counter(Storage output, int startingValue) {
this.output = output;
this.startingValue = startingValue;
}
@Override
public void run() {
try {
for( int i = startingValue; ; i++ )
output.put(i);
} catch (InterruptedException ex) {
// exit...
}
}
}
class Storage {
private final int[] buffer = new int[20];
private int head;
private int count;
public synchronized void put( int i ) throws InterruptedException {
while( count == buffer.length ) wait();// full
buffer[head++] = i;
head %= buffer.length;
count++;
notifyAll();
}
public synchronized int get() throws InterruptedException {
while( count == 0 ) wait(); // empty
int tail = (head - count) % buffer.length;
tail = (tail < 0) ? tail + buffer.length : tail;
int retval = buffer[tail];
count--;
notifyAll();
return retval;
}
}
// Consumer
class Printer implements Runnable {
private final Storage input;
public Printer(Storage input) {
this.input = input;
}
@Override
public void run() {
try {
for( ;; )
System.out.println( input.get() );
} catch (InterruptedException ex) {
// exit...
}
}
}
主线程创建 child 线程。 Parent 需要 child 的一些工作,但不是全部,因此 parent 必须等到 child 完成该工作(child 将继续做其他工作).
我想用监视器来实现它,所以我编写了以下代码:
public class WaitChildThreadMonitor {
public static final int TOTAL_COUNT_AMOUNT = 1_000;
static int count = 0;
class Child implements Runnable {
@Override
public void run() {
work();
}
public synchronized void work() {
letParentWaitForThis();
for (int i = 0; i < TOTAL_COUNT_AMOUNT; i++)
++WaitChildThreadMonitor.count;
this.notifyAll();
// More child work that parent doesn't need right now
// ...
for (int i = 0; i < TOTAL_COUNT_AMOUNT; i++)
++WaitChildThreadMonitor.count;
}
private void letParentWaitForThis() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
public synchronized void waitForWork() throws InterruptedException {
this.wait();
}
}
void main() throws InterruptedException {
Child child = new Child();
Thread childThread = new Thread(child);
// If the next two methods doesn't execute atomically,
// parent execution gets blocked forever
childThread.start();
child.waitForWork();
System.out.printf("Count value is %d\n", WaitChildThreadMonitor.count);
childThread.join();
}
public static void main(String[] args) throws InterruptedException {
(new WaitChildThreadMonitor()).main();
}
}
问题是,如果child在parent完成主要工作后执行"this.notifyAll()",然后"child.waitForWork()"执行"this.wait()",parent 不会收到通知,将永远被阻止。
我试图解决这个问题,在 child 使用 Thread.sleep() 方法开始他的工作之前强制进行上下文切换。它似乎没有按预期工作。
睡眠和不睡眠,有时 parent 会被阻塞,程序永远不会结束,有时它会正确结束(我猜是因为 parent 在 child 通知之前等待)。
我该如何解决这个问题?
提前致谢!
如果你想等待的事情已经发生,你就不能打电话给wait
。这就是调用 wait
的方法是 synchronized
的原因——因此您可以检查代表您正在等待的东西的共享状态。
所以这是一个标准的 producer-consumer 问题。很久以前,我写了一个只使用 synchronized
和 wait-notify
的实现。我看不到您的代码产生了什么;此代码仅使用 int 作为生成的内容。将 Storage
中的数组类型更改为其他 class 类型。
package quicktest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
*
* @author Brenden Towey
*/
public class ProducerConsumer {
public static void main(String[] args) throws InterruptedException {
Storage circularBuffer = new Storage();
Counter producer1 = new Counter( circularBuffer, 1000 );
Counter producer2 = new Counter( circularBuffer, 2000 );
Counter producer3 = new Counter( circularBuffer, 3000 );
Counter producer4 = new Counter( circularBuffer, 4000 );
ExecutorService exe = Executors.newCachedThreadPool();
exe.execute( producer1 );
exe.execute( producer2 );
exe.execute( producer3 );
exe.execute( producer4 );
Printer consumer = new Printer( circularBuffer );
exe.execute( consumer );
Thread.sleep( 100 );// wait a bit
exe.shutdownNow();
exe.awaitTermination( 10, TimeUnit.SECONDS );
}
}
// Producer
class Counter implements Runnable {
private final Storage output;
private final int startingValue;
public Counter(Storage output, int startingValue) {
this.output = output;
this.startingValue = startingValue;
}
@Override
public void run() {
try {
for( int i = startingValue; ; i++ )
output.put(i);
} catch (InterruptedException ex) {
// exit...
}
}
}
class Storage {
private final int[] buffer = new int[20];
private int head;
private int count;
public synchronized void put( int i ) throws InterruptedException {
while( count == buffer.length ) wait();// full
buffer[head++] = i;
head %= buffer.length;
count++;
notifyAll();
}
public synchronized int get() throws InterruptedException {
while( count == 0 ) wait(); // empty
int tail = (head - count) % buffer.length;
tail = (tail < 0) ? tail + buffer.length : tail;
int retval = buffer[tail];
count--;
notifyAll();
return retval;
}
}
// Consumer
class Printer implements Runnable {
private final Storage input;
public Printer(Storage input) {
this.input = input;
}
@Override
public void run() {
try {
for( ;; )
System.out.println( input.get() );
} catch (InterruptedException ex) {
// exit...
}
}
}