簡體   English   中英

Thread.sleep顯然不會強制上下文切換

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

主線程創建子線程。 父母需要孩子做一些工作,但不是全部,所以父母必須等到孩子完成這項工作(孩子會繼續做其他工作)。

我想用監視器實現它,所以我編寫了以下代碼:

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

}

問題是,如果孩子在完成主要工作之后執行了“ this.notifyAll()”,而在父級執行“ child.waitForWork()”中的“ this.wait()”之前執行了父級操作,則父級將不會收到通知,並且將永遠被阻止。

我試圖解決此問題,並在孩子使用Thread.sleep()方法開始工作之前強制進行上下文切換。 它似乎沒有按預期工作。

有了睡眠和沒有睡眠,有時候父母會被阻塞,程序永遠不會結束,有時它會正常結束(我想是因為父母在孩子得到通知之前就已經等待了)。

我怎樣才能解決這個問題?

提前致謝!

如果您要wait的事情已經發生,則不能致電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...
         }
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM