疑問:多生産と多消費操作値-仮死由来:『JAVAマルチスレッドプログラミングコア技術』3.1.1.1.2


詳細
JDK:1.8
背景:
マルチ生産とマルチ消費操作値-仮死をテストすると、それぞれ2つの生産と消費スレッドがあり、各スレッド内で2回の対応する方法をループします.
質問:
印刷ログによると、消費者2は1回waitが目覚めていないうちに下に実行されたことがあるが、なぜか分からない.
まずテストコードを添付します
ログに常に
消費者2 WAITING 0解除value=null消費者2 WAITING 1
正常解除valueの後には値がありますが、今回はありません.機能に影響はありませんが、おかしいと思います.

/**
 * 3.1.11.2            -  
 * Created by ironlee on 17/12/23.
 */
public class ProducerAndConsumerAllWait {

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    /**
     *   
     * @param lock
     */
    public void producer(Object lock){
        synchronized (lock){
            try {
                int i = 0 ;
                while(StringUtils.isNotBlank(getValue())) {
                    System.out.println(Thread.currentThread().getName()+" WAITING value="+getValue()+" "+(i++));
                    lock.wait();
                }
                String value = System.currentTimeMillis()+"-"+System.nanoTime();
                System.out.println(Thread.currentThread().getName()+" RUNNABLE value="+value);
                setValue(value);
                lock.notify();
//                System.out.println(System.currentTimeMillis()+"-"+System.nanoTime()+"     "+Thread.currentThread().getName()+" NOTIFY value="+getValue());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     *   
     * @param lock
     */
    public void consumer(Object lock){
        synchronized (lock){
            try{
                int i = 0 ;
//                      wait      ?
                while(StringUtils.isBlank(getValue())){
                    System.out.println(Thread.currentThread().getName()+" WAITING "+(i));
                    lock.wait();
                    System.out.println(Thread.currentThread().getName()+" WAITING "+(i) + "    value="+getValue());
                    i++;

                }
                System.out.println(Thread.currentThread().getName()+" RUNNABLE value="+getValue());
                setValue(null);
                lock.notify();
//                System.out.println(System.currentTimeMillis()+"-"+System.nanoTime()+"     "+Thread.currentThread().getName()+" NOTIFY value="+getValue());
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        final Object lock = new Object();
        final ProducerAndConsumerAllWait domain = new ProducerAndConsumerAllWait();
        final int count = 2;
        Runnable producer = new Runnable() {
                    @Override
                    public void run() {
                        synchronized (lock){
                            int i = 0 ;
                            while( i < count ){
                                System.out.println( Thread.currentThread().getName()+"   ="+i);
                                domain.producer( lock );
                                i++;
                            }
                        }
                    }
                };
        Runnable consumer = new Runnable() {
                    @Override
                    public void run() {
                        synchronized (lock){
                            int i = 0 ;
                            while(i< count){
                                System.out.println( Thread.currentThread().getName()+"   ="+i);
                                domain.consumer( lock );
                                i++;
                            }
                        }
                    }
                };
                for( int ii = 0 ; ii < 2 ; ii++){
                    Thread producerT = new Thread(producer);
                    producerT.setName("   "+(ii+1));
                    producerT.start();
                    Thread consumerT = new Thread(consumer);
                    consumerT.setName("   "+(ii+1));
                    consumerT.start();
                }
        try {
            Thread.sleep( 1000L );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread[] threadArray = new Thread[Thread.currentThread().getThreadGroup().activeCount()];
        Thread.currentThread().getThreadGroup().enumerate( threadArray );
        for( Thread t : threadArray ){
            System.out.println( t.getName() + " " + t.getState() );
        }
    }
}