zoukankan      html  css  js  c++  java
  • 多线程相关wait()和notify()

    • wait()和notify()

      wait会释放锁,notify不会释放锁。必须与synchronize使用。。。

     1 /**
     2  * 曾经的面试题:(淘宝?)
     3  * 实现一个容器,提供两个方法,add,size
     4  * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
     5  * 
     6  * 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
     7  * 
     8  * 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
     9  * 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
    10  * 14  * 
    15  * notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
    16  * 整个通信过程比较繁琐
    17  * @author mashibing
    18  */
    19 package com.concurrent.c019;
    20 
    21 import java.util.ArrayList;
    22 import java.util.List;
    23 import java.util.concurrent.TimeUnit;
    24 
    25 
    26 public class MyContainer4 {
    27 
    28     //添加volatile,使t2能够得到通知
    29     volatile List lists = new ArrayList();
    30 
    31     public void add(Object o) {
    32         lists.add(o);
    33     }
    34 
    35     public int size() {
    36         return lists.size();
    37     }
    38     
    39     public static void main(String[] args) {
    40         MyContainer4 c = new MyContainer4();
    41         
    42         final Object lock = new Object();
    43         
    44         new Thread(() -> {
    45             synchronized(lock) {
    46                 System.out.println("t2启动");
    47                 if(c.size() != 5) {
    48                     try {
    49                         lock.wait();
    50                     } catch (InterruptedException e) {
    51                         e.printStackTrace();
    52                     }
    53                 }
    54                 System.out.println("t2 结束");
    55                 //通知t1继续执行
    56                 lock.notify();
    57             }
    58             
    59         }, "t2").start();
    60         
    61         try {
    62             TimeUnit.SECONDS.sleep(1);
    63         } catch (InterruptedException e1) {
    64             e1.printStackTrace();
    65         }
    66 
    67         new Thread(() -> {
    68             System.out.println("t1启动");
    69             synchronized(lock) {
    70                 for(int i=0; i<10; i++) {
    71                     c.add(new Object());
    72                     System.out.println("add " + i);
    73                     
    74                     if(c.size() == 5) {
    75                         lock.notify();
    76                         //释放锁,让t2得以执行
    77                         try {
    78                             lock.wait();
    79                         } catch (InterruptedException e) {
    80                             e.printStackTrace();
    81                         }
    82                     }
    83                     
    84                     try {
    85                         TimeUnit.SECONDS.sleep(1);
    86                     } catch (InterruptedException e) {
    87                         e.printStackTrace();
    88                     }
    89                 }
    90             }
    91         }, "t1").start();
    92         
    93         
    94     }
    95 }

    ==============================

    另一种使用CountDown

     1 /**
     2  * 曾经的面试题:(淘宝?)
     3  * 实现一个容器,提供两个方法,add,size
     4  * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
     5  * 
     6  * 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
     7  * 
     8  * 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
     9  * 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
    10  * 
    11  * 阅读下面的程序,并分析输出结果
    12  * 可以读到输出结果并不是size=5时t2退出,而是t1结束时t2才接收到通知而退出
    13  * 想想这是为什么?
    14  * 
    15  * notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
    16  * 整个通信过程比较繁琐
    17  * 
    18  * 使用Latch(门闩)替代wait notify来进行通知
    19  * 好处是通信方式简单,同时也可以指定等待时间
    20  * 使用await和countdown方法替代wait和notify
    21  * CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行
    22  * 当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify就显得太重了
    23  * 这时应该考虑countdownlatch/cyclicbarrier/semaphore
    24  * @author mashibing
    25  */
    26 package com.concurrent.c019;
    27 
    28 import java.util.ArrayList;
    29 import java.util.List;
    30 import java.util.concurrent.CountDownLatch;
    31 import java.util.concurrent.TimeUnit;
    32 
    33 public class MyContainer5 {
    34 
    35     // 添加volatile,使t2能够得到通知
    36     volatile List lists = new ArrayList();
    37 
    38     public void add(Object o) {
    39         lists.add(o);
    40     }
    41 
    42     public int size() {
    43         return lists.size();
    44     }
    45 
    46     public static void main(String[] args) {
    47         MyContainer5 c = new MyContainer5();
    48 
    49         CountDownLatch latch = new CountDownLatch(1);
    50 
    51         new Thread(() -> {
    52             System.out.println("t2启动");
    53             if (c.size() != 5) {
    54                 try {
    55                     latch.await();
    56                     
    57                     //也可以指定等待时间
    58                     //latch.await(5000, TimeUnit.MILLISECONDS);
    59                 } catch (InterruptedException e) {
    60                     e.printStackTrace();
    61                 }
    62             }
    63             System.out.println("t2 结束");
    64 
    65         }, "t2").start();
    66 
    67         try {
    68             TimeUnit.SECONDS.sleep(1);
    69         } catch (InterruptedException e1) {
    70             e1.printStackTrace();
    71         }
    72 
    73         new Thread(() -> {
    74             System.out.println("t1启动");
    75             for (int i = 0; i < 10; i++) {
    76                 c.add(new Object());
    77                 System.out.println("add " + i);
    78 
    79                 if (c.size() == 5) {
    80                     // 打开门闩,让t2得以执行
    81                     latch.countDown();
    82                 }
    83 
    84                 try {
    85                     TimeUnit.SECONDS.sleep(1);
    86                 } catch (InterruptedException e) {
    87                     e.printStackTrace();
    88                 }
    89             }
    90 
    91         }, "t1").start();
    92 
    93     }
    94 }
  • 相关阅读:
    JavaScript学习笔记--this全面解析
    CSS3学习笔记--animation和transition
    HTML5学习笔记--HTML5新增的常用标签
    布局学习笔记--flex布局
    布局学习笔记--rem布局
    HTML5学习笔记--Canvas
    react-pdf插件实现pdf预览功能
    postman基础使用——调试接口
    react 实现复制copy文本内容
    react 移动端签名实现
  • 原文地址:https://www.cnblogs.com/zchok/p/12972209.html
Copyright © 2011-2022 走看看