zoukankan      html  css  js  c++  java
  • Java多线程之wait/notify/notifyAll

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 import java.util.concurrent.TimeUnit;
     4 
     5 /**
     6  * 创建一个容器,一根线程往里放东西,一根线程判断是否符合条件
     7  */
     8 public class MyContainer2 {
     9 
    10     /*volatile*/ List<Object> list = new ArrayList<>();  //内存不可见
    11 
    12     void add(Object o) {
    13         try {
    14             TimeUnit.SECONDS.sleep(1);
    15         } catch (InterruptedException e) {
    16             e.printStackTrace();
    17         }
    18         list.add(o);
    19         System.out.println(Thread.currentThread().getName() + " add:" + o);
    20     }
    21 
    22     int getSize() {
    23         return this.list.size();
    24     }
    25 
    26     public static void main(String[] args) {
    27 
    28         MyContainer2 container = new MyContainer2();
    29 
    30         new Thread(() -> {
    31             for(int i=0; i<10; i++) {
    32                 container.add("Object" + i);
    33             }
    34         }, "线程1").start();
    35 
    36         new Thread(() -> {
    37             while (true) { //很浪费cpu资源
    38                 if(container.getSize() > 5) break;
    39             }
    40             System.out.println(Thread.currentThread().getName() + "结束");
    41         }, "线程2").start();
    42     }
    43 }

    看明白接着看,上面代码while(true)很消耗cpu资源,下面代码用到wait和notify,阻塞线程和唤醒线程:

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 import java.util.concurrent.TimeUnit;
     4 
     5 /**
     6  * wait 线程会失去锁
     7  *
     8  * notify/notifyAll 叫醒线程 不会释放锁
     9  *
    10  */
    11 public class MyContainer3 {
    12 
    13     volatile List<Object> list = new ArrayList<>();
    14 
    15     void add(Object o) {
    16         try {
    17             TimeUnit.SECONDS.sleep(1);
    18         } catch (InterruptedException e) {
    19             e.printStackTrace();
    20         }
    21         list.add(o);
    22         System.out.println(Thread.currentThread().getName() + " add:" + o);
    23     }
    24 
    25     int getSize() {
    26         return this.list.size();
    27     }
    28 
    29     public static void main(String[] args) {
    30 
    31         MyContainer3 container = new MyContainer3();
    32 
    33         final Object block = new Object(); //
    34 
    35         new Thread(() -> {
    36             synchronized (block) {
    37                 System.out.println(Thread.currentThread().getName() + "开始");
    38                 if(container.getSize() < 5) {
    39                     try {
    40                         System.out.println(Thread.currentThread().getName() + "阻塞");
    41                         block.wait();
    42                     } catch (InterruptedException e) {
    43                         e.printStackTrace();
    44                     }
    45                 }
    46                 System.out.println(Thread.currentThread().getName() + "结束");
    47             }
    48         }, "线程2").start();
    49 
    50         new Thread(() -> {
    51             synchronized (block) {
    52                 for(int i=0; i<10; i++) {
    53                     container.add("Object" + i);
    54 
    55                     if(i > 5) {
    56                         block.notify(); //当唤醒在block上等待的线程后,线程1并不会失去锁,需要等线程1执行完毕释放锁,线程2才能接着执行。
    57                     }
    58 
    59                     try {
    60                         TimeUnit.SECONDS.sleep(1);
    61                     } catch (InterruptedException e) {
    62                         e.printStackTrace();
    63                     }
    64                 }
    65             }
    66         }, "线程1").start();
    67 
    68     }
    69 
    70 }

    看明白接着看,上面线程执行效果不理想,下面进行了修改:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    /**
     * wait 失去锁
     *
     * notify/notifyAll 叫醒线程 不会释放锁
     *
     * wait和notify/notifyAll要在synchronized代码块里
     *
     * MyContainer3 改良版
     *
     */
    public class MyContainer4 {
    
        volatile List<Object> list = new ArrayList<>();
    
        void add(Object o) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(o);
            System.out.println(Thread.currentThread().getName() + " add:" + o);
        }
    
        int getSize() {
            return this.list.size();
        }
    
        public static void main(String[] args) {
    
            MyContainer4 container = new MyContainer4();
    
            final Object block = new Object(); //
    
            new Thread(() -> {
                synchronized (block) {
                    System.out.println(Thread.currentThread().getName() + "开始");
                    if(container.getSize() < 5) {
                        try {
                            System.out.println(Thread.currentThread().getName() + "阻塞");
                            block.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + "结束");
                    block.notify(); //唤醒线程1,继续执行
                }
            }, "线程2").start();
    
            new Thread(() -> {
                synchronized (block) {
                    for(int i=0; i<10; i++) {
                        container.add("Object" + i);
    
                        if(container.getSize() == 5) {
                            block.notify(); //当唤醒在block上等待的线程后,线程1并不会失去锁,需要等线程1执行完毕释放锁,线程2才能接着执行。
                            try {
                                block.wait(); //唤醒线程2,释放掉线程1的锁
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
    
                        try {
                            TimeUnit.SECONDS.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }, "线程1").start();
    
        }
    
    }

    看明白接着看,下面代码用到CountDownLatch,实现上面wait和notify的效果:

     1 import java.util.ArrayList;
     2 import java.util.List;
     3 import java.util.concurrent.CountDownLatch;
     4 import java.util.concurrent.TimeUnit;
     5 
     6 /**
     7  *
     8  * MyContainer4 改良版
     9  *
    10  * 较MyContainer4 效率更高
    11  *
    12  */
    13 public class MyContainer5 {
    14 
    15     volatile List<Object> list = new ArrayList<>();
    16 
    17     void add(Object o) {
    18         try {
    19             TimeUnit.SECONDS.sleep(1);
    20         } catch (InterruptedException e) {
    21             e.printStackTrace();
    22         }
    23         list.add(o);
    24         System.out.println(Thread.currentThread().getName() + " add:" + o);
    25     }
    26 
    27     int getSize() {
    28         return this.list.size();
    29     }
    30 
    31     public static void main(String[] args) {
    32 
    33         MyContainer5 container = new MyContainer5();
    34 
    35         //final Object block = new Object(); //
    36         CountDownLatch latch = new CountDownLatch(5);
    37 
    38         new Thread(() -> {
    39             //synchronized (block) {
    40                 System.out.println(Thread.currentThread().getName() + "开始");
    41                 if(container.getSize() < 5) {
    42                     //try {
    43                     System.out.println(Thread.currentThread().getName() + "阻塞");
    44                     try {
    45                         latch.await(); //等待门闩打开
    46                     } catch (InterruptedException e) {
    47                         e.printStackTrace();
    48                     }
    49                     //block.wait();
    50                     //} catch (InterruptedException e) {
    51                         //e.printStackTrace();
    52                     //}
    53                 }
    54                 System.out.println(Thread.currentThread().getName() + "结束");
    55                 //block.notify(); //唤醒线程1,继续执行
    56             //}
    57         }, "线程2").start();
    58 
    59         new Thread(() -> {
    60             //synchronized (block) {
    61                 for(int i=0; i<10; i++) {
    62                     container.add("Object" + i);
    63 
    64                     //if(container.getSize() == 5) {
    65                         //block.notify(); //当唤醒在block上等待的线程后,线程1并不会失去锁,需要等线程1执行完毕释放锁,线程2才能接着执行。
    66                         //try {
    67                             //block.wait(); //唤醒线程2,释放掉线程1的锁
    68                         //} catch (InterruptedException e) {
    69                             //e.printStackTrace();
    70                         //}
    71                     //}
    72 
    73                     latch.countDown(); //打开门闩,让线程2继续执行
    74 
    75                     try {
    76                         TimeUnit.SECONDS.sleep(1);
    77                     } catch (InterruptedException e) {
    78                         e.printStackTrace();
    79                     }
    80                 }
    81             //}
    82         }, "线程1").start();
    83 
    84     }
    85 
    86 }
  • 相关阅读:
    视频分解图片,图片合成视频
    获取图片中指定区域图片
    CALayer alpha mask not working
    多媒体编程ios摄像头图像抓取工具类
    10月17日
    10月16日
    10月15日
    10月14日
    10月13日
    10月12日
  • 原文地址:https://www.cnblogs.com/mxh-java/p/12246370.html
Copyright © 2011-2022 走看看