简体   繁体   English

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

[英]Thread.sleep doesn't force context switch apparently

Main thread creates child thread. 主线程创建子线程。 Parent needs some work from child, but not all of it, so parent must wait until child finish that work (child will keep doing some other work). 父母需要孩子做一些工作,但不是全部,所以父母必须等到孩子完成这项工作(孩子会继续做其他工作)。

I would like to achieve it with monitors so I coded the following: 我想用监视器实现它,所以我编写了以下代码:

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();
}

} }

The problem is that if child executes "this.notifyAll()" after he finished his main work before parent executes "this.wait()" in "child.waitForWork()", parent won't get notified and will get blocked forever. 问题是,如果孩子在完成主要工作之后执行了“ this.notifyAll()”,而在父级执行“ child.waitForWork()”中的“ this.wait()”之前执行了父级操作,则父级将不会收到通知,并且将永远被阻止。

I tried to solve it forcing a context switch before child start his work using Thread.sleep() method. 我试图解决此问题,并在孩子使用Thread.sleep()方法开始工作之前强制进行上下文切换。 It doesn't seem to work as expected. 它似乎没有按预期工作。

With sleep and without sleep, sometimes parent gets blocked and program never ends, sometimes it ends properly (I guess because parent waited before child notified). 有了睡眠和没有睡眠,有时候父母会被阻塞,程序永远不会结束,有时它会正常结束(我想是因为父母在孩子得到通知之前就已经等待了)。

How can I fix this? 我怎样才能解决这个问题?

Thanks in advance! 提前致谢!

You must not call wait if the thing you want to wait for has already happened. 如果您要wait的事情已经发生,则不能致电wait That's the reason the method that calls wait is synchronized -- so you can check the shared state that represents the thing you're waiting for. 这就是调用wait的方法被synchronized的原因-因此您可以检查代表您正在等待的事物的共享状态。

So this is a standard producer-consumer problem. 因此,这是一个标准的生产者-消费者问题。 A long time ago, I wrote an implementation using only synchronized and wait-notify . 很久以前,我写了一个只使用synchronizedwait-notify I don't see what your code produces; 我看不到您的代码产生了什么; this code just uses int as the thing produced. 此代码仅将int用作产生的东西。 Change the type of the array inside Storage for some other class type. 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...
         }
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM