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

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

作者: 迷糊小生 | 来源:发表于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