写两个线程,线程1添加10个元素到容器,线程2对元素个数做监控,个数为5时,线程2给出提示并结束

思路:开启两个线程,线程t1添加元素,线程t2监控元素个数为5。如何保证元素个数为5的时候t2执行,这里就思考如何再元素个数为5的时候t2拿到锁执行,t1等待。直到t2执行完之后t1再拿到锁。

第一种方法:

public class waitFiveSecondTest {
     volatile List list = new ArrayList<>();
     public void add(Object o){
         list.add(o);
     }
     public int size(){
         return list.size();
     }

    public static void main(String[] args) {
        waitFiveSecondTest w = new waitFiveSecondTest();
        final Object lock = new Object();
        new Thread(()->{
            System.out.println("t2启动鸟");
            synchronized (lock){
                if(w.size()!=5){          
                    try {
                        lock.wait();          //1、t2先执行,元素个数还没有到5的时候wait()等待,释放锁给t1。
                                              //2、直到t1wait()释放了锁之后,t2重新拿到锁执行
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("t2执行结束鸟");  
                lock.notify();          //3、t2执行完了之后,需要唤醒t1,直到t2执行完之后锁释放。t1拿到继续添加元素
            }
        },"t2").start();                  
        new Thread(()->{
            synchronized (lock){
                System.out.println("t1启动鸟");      //t1拿到锁了开始启动执行添加元素
                for (int i = 0; i <10 ; i++) {
                    w.add(new Object());
                    System.out.println("add"+i);
                    if(w.size()==5){         //t1往容器里面添加元素到5的时候
                        lock.notify();       //notify唤醒t2.但是notify不会释放锁,所以t2还不能执行
                        try {
                            lock.wait();     //那么需要让t1释放锁,让t2拿到。直到t2执行完,并唤醒t1,t1继续执行
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("t1执行结束鸟");
            }
        },"t1").start();
    }
}

 方法一程序略微复杂。其实就是使用了wait和notyfy方法来控制锁。这里首先要理解wait()是释放了锁的,但是notyfy()没有释放锁。所以需要注意。

 

接着看下方法二:对于方法1的优化,方法1之所以复杂就是因为控制锁的时候需要两个线程协调锁。所以要程序更简单使用一个控制锁的flag就好,这里使用门栓CountDownLatch。CountDownLatch中值1-->0的时候们拴就开了,countDown()方法开拴。仍然是上面的思路,t2等待,t1添加元素到5给t2执行。

public class waitFiveSecondTest {
     volatile List list = new ArrayList<>();
     public void add(Object o){
         list.add(o);
     }

     public int size(){
         return list.size();
     }

    public static void main(String[] args) {
        waitFiveSecondTest w = new waitFiveSecondTest();
        CountDownLatch latch= new CountDownLatch(1);
        new Thread(()->{
            System.out.println("t2启动鸟");
            if(w.size()!=5){
                try {
                    latch.await();     //等着开门,await不需要锁定任何对象。
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t2执行结束鸟");

        },"t2").start();

        new Thread(()->{
            System.out.println("t1启动鸟");
                for (int i = 0; i <10 ; i++) {
                    w.add(new Object());
                    System.out.println("add"+i);
                    if(w.size()==5){
                        latch.countDown();
                    }
                }
                System.out.println("t1执行结束鸟");
        },"t1").start();

    }

}

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页