多线程操作中为什么使用while而不是if来做判断状态是否就绪

假设有三个线程ABC,A为生产者线程,B为消费者线程,C为破坏者线程。三个线程都访问一个共享对象,C进入的时候,通过调用
notifyAll的方法,把所有的wait唤醒,如果用了if,代码会往下进行,会导致无法获取到元素或者删除元素。如果是while就不一样了,就会继续检查条件。

1.容器类EventStoage.java

package sss;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

public class EventStorage {
    private int maxSize;
    private List<Date> storage;
    public EventStorage(){
        maxSize=1;
        storage=new LinkedList<>();
    }
    
    
    public synchronized void destory() {
    	notifyAll();
    }
    
    public synchronized void set(){
        if (storage.size()==maxSize){
            try {
                wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        ((LinkedList<Date>) storage).offer(new Date());
        System.out.printf("Set: %d\n",storage.size());
        notifyAll();
    }
    public synchronized void get(){
    	if (storage.size()==0){
            try {
                wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        }
        System.out.printf("Get: %d: %s\n",storage.
        size(),((LinkedList<?>)storage).poll());
        notifyAll();
    }
}

2.生产者

package sss;

public class Producer implements Runnable {
    private EventStorage storage;
    public Producer(EventStorage storage){
        this.storage=storage;
    }
    @Override
    public void run() {
        for (int i=0; i<10; i++){
            storage.set();
        }
    }
 }

3.消费者

package sss;

public class Consumer implements Runnable {
    private EventStorage storage;
    public Consumer(EventStorage storage){
        this.storage=storage;
    }
    @Override
    public void run() {
        for (int i=0; i<10; i++){
            storage.get();
        }
    }
}

4.测试类

package sss;

public class Main {
	public static void main(String[] args) {
		EventStorage storage=new EventStorage();
		Producer producer=new Producer(storage);
		Thread A=new Thread(producer);
		Consumer consumer=new Consumer(storage);
		Thread B=new Thread(consumer);
		A.start();

		//破坏者线程C
		Thread C=new Thread(new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				storage.destory();
			}
		});
		
		B.start();
		C.start();
	}
}

测试结果:

当然,你也可能不出错,因为线程的运行时机是不定的。

如果你把if改成while,就不会出现线程安全问题了,测试结果如下



猜你喜欢

转载自blog.csdn.net/u012150590/article/details/80445464