Thread.sleep 显然不会强制上下文切换



主线程创建子线程。父母需要孩子做一些工作,但不是全部,所以父母必须等到孩子完成这项工作(孩子会继续做其他工作(。

我想用显示器来实现它,所以我编写了以下内容:

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 %dn", WaitChildThreadMonitor.count);
    childThread.join();
}
public static void main(String[] args) throws InterruptedException {
    (new WaitChildThreadMonitor()).main();
}

}

问题是,如果孩子在完成主要工作后执行"this.notifyAll((",然后父在"child.waitForWork(("中执行"this.wait((",则父级将不会收到通知,并将永远被阻止。

我试图解决它,在孩子使用 Thread.sleep(( 方法开始工作之前强制上下文切换。它似乎没有按预期工作。

有睡眠和不睡觉,有时父母会被阻止,程序永远不会结束,有时它会正确结束(我猜是因为父母在通知孩子之前等待(。

我该如何解决这个问题?

提前感谢!

如果你想等待的事情已经发生,你一定不要打电话给wait。这就是调用wait的方法synchronized的原因 - 因此您可以检查表示您正在等待的事物的共享状态。

所以这是一个标准的生产者-消费者问题。 很久以前,我只用synchronizedwait-notify编写了一个实现。 我没有看到你的代码产生了什么;这段代码只使用 int 作为生成的东西。 更改 Storage 中数组的类型,以便使用其他类类型。

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...
         }
   }
}

最新更新