美文网首页
多线程等待/通知(两个要点)

多线程等待/通知(两个要点)

作者: 迷糊小生 | 来源:发表于2019-03-31 21:12 被阅读0次
public class Add {

    private String lock;
    
    public Add(String lock) {
        this.lock = lock;
    }
    
    public void add() {
        synchronized (lock) {
            ValueObject.list.add("anyString");
            lock.notifyAll();
        }
    }
}
package other.thread11;

public class Subtract {

    private String lock;
    
    public Subtract(String lock) {
        this.lock = lock;
    }
    
    public void subtract() {
        try {
            synchronized (lock) {
                if(ValueObject.list.size() == 0) {
                    System.out.println("wait begin ThreadName=" + Thread.currentThread().getName());
                    lock.wait();
                    System.out.println("wait end ThreadName=" + Thread.currentThread().getName());
                }
                ValueObject.list.remove(0);
                System.out.println(Thread.currentThread().getName() + "  list size:" + ValueObject.list.size());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

package other.thread11;

public class ThreadA extends Thread{

    private Add p;
    public ThreadA(Add p) {
        this.p = p;
    }
    
    @Override
    public void run() {
        p.add();
    }
}
package other.thread11;

public class ThreadB extends Thread{

    private Subtract s;
    public ThreadB(Subtract s) {
        this.s = s;
    }
    
    @Override
    public void run() {
        s.subtract();
    }
}
public class ValueObject {

    public static List list = new ArrayList<>();
    
}
package other.thread11;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        String lock = new String("");
        Add add = new Add(lock);
        Subtract sub = new Subtract(lock);
        ThreadB threadB = new ThreadB(sub);
        threadB.setName("B");
        threadB.start();
        Subtract sub2 = new Subtract(lock);
        ThreadB threadB2 = new ThreadB(sub2);
        threadB2.setName("B2");
        threadB2.start();
        Thread.sleep(1000);
        ThreadA threadA = new ThreadA(add);
        threadA.setName("A");
        threadA.start();
    }
}

image.png

错误原因:当第一个线程进入到subtract()方法后由于ValueObject.list大小为0而进入了等待状态,并且释放了锁,第二个线程同样因此而进入了等到状态,直至add()方法执行完毕唤醒了之前两个线程,两个线程之一获得了锁对象执行完了subtract()方法,而另外一个线程被唤醒再次得到锁对象时继续运行下面代码,直至移除的时候抛出数组越界异常。

image.png

解决方案:将if改为while,这样的话第二个等待线程被唤醒后将再次校验ValueObject.list大小,如果为0的话将再次进入等待状态

package other.thread12;
//消费者
public class Customer {

    private String lock;
    
    public Customer(String lock) {
        this.lock = lock;
    }
    
    public void getValue() {
        try {
            synchronized (lock) {
                if(ValueObject.value.equals("")) {
                    System.out.println("Customer...." + Thread.currentThread().getName()
                            + "waiting....");
                    lock.wait();
                }
                System.out.println("get:" + ValueObject.value);
                ValueObject.value = "";
                lock.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
}
package other.thread12;
//生产者
public class Product {

    private String lock;
    
    public Product(String lock) {
        this.lock = lock;
    }
    
    public void setValue() {
        try {
            synchronized (lock) {
                if(!ValueObject.value.equals("")) {
                    System.out.println("PRODUCT...." + Thread.currentThread().getName()
                            + "waiting....");
                    lock.wait();
                }
                String value = System.currentTimeMillis() + "_" + System.nanoTime();
                System.out.println("set:" + value);
                ValueObject.value = value;
                lock.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
}
package other.thread12;

public class ThreadA extends Thread{

    private Product product;
    public ThreadA(Product product) {
        this.product = product;
    }
    
    @Override
    public void run() {
        while (true) {
            product.setValue();
            
        }
    }
}
package other.thread12;

public class ThreadB extends Thread {

    private Customer customer;

    public ThreadB(Customer customer) {
        this.customer = customer;
    }

    @Override
    public void run() {
        while (true) {
            customer.getValue();
        }
    }
}
package other.thread12;

public class ValueObject {

    public static String value = "";

}
public class Test {
    public static void main(String[] args) {
        String lock = new String("");
        Product product = new Product(lock);
        ThreadA[] threadA = new ThreadA[2];
        Customer customer = new Customer(lock);
        ThreadB[] threadB = new ThreadB[2];
        for (int i = 0; i < 2; i++) {
            threadA[i] = new ThreadA(product);
            threadA[i].setName("PRODUCT " + (i + 1));
            threadB[i] = new ThreadB(customer);
            threadB[i].setName("Customer " + (i + 1));
            threadA[i].start();
            threadB[i].start();
        }
    }
}
image.png

在多个生成者和多个消费者的时候由于notify()方法是随机唤醒一个的缘故,因此会造成大亮线程处于等待状态。

解决方案:notify()替换成notifyAll();

相关文章

网友评论

      本文标题:多线程等待/通知(两个要点)

      本文链接:https://www.haomeiwen.com/subject/kbzubqtx.html