如何知道线程是否被唤醒或时间切片(生产者 - 消费者)

时间:2015-10-01 05:18:43

标签: java multithreading

我正在学习java中的多线程,并且我遇到了一个我无法理解的行为。

之前,一些解释:生产者需要生产,直到列表满了。生产时,没有什么能阻止消费者消费。消费者消耗直到列表为空。当列表具有< 10个元素时,生产者才开始生产。

这是我的代码:

制作人类

class Producer extends Thread {
    private MyList list;
    public Producer(MyList list) {
       this.list = list;
    }

    public void run() {
    for (int i = 0; i < 1000; i++) {
        try {
           list.put();
        } catch (InterruptedException e) {
           System.out.println("I WAS INTERRUPTED");
        }
    }
    }
}

消费

class Consumer extends Thread {

    private MyList list;
    public Consumer(MyList list) {
       this.list = list;    
    }
    public void run() {
    for (int i = 0; i < 1000; i++) {
        try {
           list.get();
        } catch (InterruptedException e) {
           System.out.println("I WAS INTERRUPTED 2");
        }
    }
    }
}

具有共享资源的列表

    public class MyList {

        private String[] dates = new String[100];
        private int index = -1;

        public int getIndex() {
           return index;
        }

        public synchronized void put() throws InterruptedException {

        if ((getIndex() + 1) == 100) {     
            System.out.println("List is full");
            wait();
        }


    /**
     * Here I need to know if this thread was woke up by the consumer, or it was 'restaured' due time-slice
     * 
     */

        if (Thread.currentThread().isInterrupted() && getIndex() >= 10) {
            System.out.println("List doesn't have the minimun quantity to start a production");
            wait();
        }

        dates[++index] = new Date().toString();
        System.out.println("put " + dates[index] + " at " + index);
        notifyAll();
        }

        public synchronized void get() throws InterruptedException {

        if (getIndex() < 0)
            wait();

        System.out.println("got " + dates[index--] + " at " + (index + 1));

      /**
     * Basically, to this example work I would need to put, if (getIndex() < 10) notifyAll() here,
     *  but that is a behavior for the producer and should not be in the consumer
     * 
     */
         notifyAll();

        }
    }

然后

public class Main {

    public static void main(String[] args) {

    MyList list = new MyList();

    Thread producer = new Producer(list);
    Thread consumer = new Consumer(list);

    producer.start();
    consumer.start();
    }
}

对不起那堆代码,但这不是复杂的代码:)

好的,怀疑,为什么那些I WAS INTERRUPTED从未被召唤过?

以及为什么(可能与上述相关)List doesn't have the minimun quantity to start a production也从未被调用过?

实际输出:

....
....
put Thu Oct 01 02:15:12 BRT 2015 at 93
put Thu Oct 01 02:15:12 BRT 2015 at 94
put Thu Oct 01 02:15:12 BRT 2015 at 95
put Thu Oct 01 02:15:12 BRT 2015 at 96
put Thu Oct 01 02:15:12 BRT 2015 at 97
put Thu Oct 01 02:15:12 BRT 2015 at 98
put Thu Oct 01 02:15:12 BRT 2015 at 99
List is full
got Thu Oct 01 02:15:12 BRT 2015 at 99
put Thu Oct 01 02:15:12 BRT 2015 at 99 <- this wouldn't happen
List is full
got Thu Oct 01 02:15:12 BRT 2015 at 99
put Thu Oct 01 02:15:12 BRT 2015 at 99 <- this wouldn't happen
List is full
...
...

修改

我对这些事感到困惑,我从不在代码中调用中断,但这不是我的目的。

我想知道线程何时被另一个线程'唤醒'而不是因为时间片而被jvm唤醒

1 个答案:

答案 0 :(得分:0)

您没有调用interrupt()方法来中断线程。在main方法中尝试以下代码:

producer.start();
consumer.start();
producer.interrupt();
consumer.interrupt();

以下是一个示例输出:

put Thu Oct 01 10:56:10 IST 2015 at 10 List doesn't have the minimun quantity to start a production I WAS INTERRUPTED got Thu Oct 01 10:56:10 IST 2015 at 10 got Thu Oct 01 10:56:10 IST 2015 at 9 got Thu Oct 01 10:56:10 IST 2015 at 8 got Thu Oct 01 10:56:10 IST 2015 at 7 got Thu Oct 01 10:56:10 IST 2015 at 6 got Thu Oct 01 10:56:10 IST 2015 at 5 got Thu Oct 01 10:56:10 IST 2015 at 4 got Thu Oct 01 10:56:10 IST 2015 at 3 got Thu Oct 01 10:56:10 IST 2015 at 2 got Thu Oct 01 10:56:10 IST 2015 at 1 got Thu Oct 01 10:56:10 IST 2015 at 0 I WAS INTERRUPTED 2 put Thu Oct 01 10:56:10 IST 2015 at 0

要点注意事项(摘自官方tutorial):

  1. 线程通过在interrupt对象上调用Thread来发送中断,以便线程被中断。为使中断机制正常工作,被中断的线程必须支持自己的中断。
  2. 使用称为interrupt status的内部标志实现中断机制。调用Thread.interrupt设置此标志。当线程通过调用静态方法Thread.interrupted检查中断时,中断状态被清除。非静态isInterrupted方法(由一个线程用于查询另一个线程的中断状态)不会更改中断状态标志。