• 线程方法wait()和notify()的使用


    实现需求:

    开启2个线程,1个线程对某个int类型成员变量加1,另外1个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

    代码如下

     1 package test;
     2 
     3 public class Sample {
     4 
     5     private int i;
     6 
     7     public synchronized void increase() {
     8 
     9         if(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
    10             try {
    11                 wait();
    12             } catch (Exception e) {
    13                 e.printStackTrace();
    14             }
    15         }
    16 
    17         // 值为0,需要增加
    18         i++;
    19         System.out.println(i);
    20         // 通知其他线程,可以进行减1的操作了
    21         notify();
    22     }
    23 
    24     public synchronized void decrease() {
    25         if(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
    26             try {
    27                 wait();
    28             } catch (Exception e) {
    29                 e.printStackTrace();
    30             }
    31         }
    32 
    33         // 值为1,需要减少
    34         i--;
    35         System.out.println(i);
    36         // 通知其他线程,可以进行加1的操作了
    37         notify();
    38     }
    39 
    40     public static void main(String[] args) {
    41 
    42         Sample sample = new Sample();
    43 
    44         Thread t1 = new IncreaseThread(sample);
    45         Thread t2 = new DecreaseThread(sample);
    46 
    47         t1.start();
    48         t2.start();
    49     }
    50 }
    51 
    52 class DecreaseThread extends Thread {
    53 
    54     private Sample sample;
    55 
    56     public DecreaseThread(Sample sample) {
    57         this.sample = sample;
    58     }
    59 
    60     @Override
    61     public void run() {
    62         for (int i = 0; i < 20; i++) {
    63             try {
    64                 Thread.sleep((long) Math.random() * 1000);
    65             } catch (Exception e) {
    66                 e.printStackTrace();
    67             }
    68 
    69             sample.decrease();
    70         }
    71     }
    72 }
    73 
    74 class IncreaseThread extends Thread {
    75 
    76     private Sample sample;
    77 
    78     public IncreaseThread(Sample sample) {
    79         this.sample = sample;
    80     }
    81 
    82     @Override
    83     public void run() {
    84         for (int i = 0; i < 20; i++) {
    85             try {
    86                 Thread.sleep((long) Math.random() * 1000);
    87             } catch (Exception e) {
    88                 e.printStackTrace();
    89             }
    90 
    91             sample.increase();
    92         }
    93     }
    94 }

    需求稍作改变,变成:

    开启4个线程,2个线程对某个int类型成员变量加1,另外2个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

    如果是直接再生成t3 t4分别是IncreaseThread和DecreaseThread的实例(即t1/t3为IncreaseThread类的实例,t2/t4为DecreaseThread的实例),假设执行流程如下:

    (1)t2执行,由于i=0,所以线程等待,释放锁,随机通知一条线程进行执行(notify()方法是通知随机一条线程的)

    (2)假设通知到了t4,由于i=0,所以t4线程又等待,锁释放,又随机通知到一条线程进行执行

    (3)假设又通知到了t2线程,这个时候,线程的执行是从wait()方法后面开始执行的,不会再去判断i是否等于0了,继续执行,会进行i的自减操作,出现i=-1的局面

    所以代码需要修改

     1 package test;
     2 
     3 public class Sample {
     4 
     5     private int i;
     6 
     7     public synchronized void increase() {
     8 
     9         while(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
    10             try {
    11                 wait();
    12             } catch (Exception e) {
    13                 e.printStackTrace();
    14             }
    15         }
    16 
    17         // 值为0,需要增加
    18         i++;
    19         System.out.println(i);
    20         // 通知其他线程,可以进行减1的操作了
    21         notify();
    22     }
    23 
    24     public synchronized void decrease() {
    25         while(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
    26             try {
    27                 wait();
    28             } catch (Exception e) {
    29                 e.printStackTrace();
    30             }
    31         }
    32 
    33         // 值为1,需要减少
    34         i--;
    35         System.out.println(i);
    36         // 通知其他线程,可以进行加1的操作了
    37         notify();
    38     }
    39 
    40     public static void main(String[] args) {
    41 
    42         Sample sample = new Sample();
    43 
    44         Thread t1 = new IncreaseThread(sample);
    45         Thread t2 = new DecreaseThread(sample);
    46         Thread t3 = new IncreaseThread(sample);
    47         Thread t4 = new DecreaseThread(sample);
    48 
    49         t1.start();
    50         t2.start();
    51         t3.start();
    52         t4.start();
    53     }
    54 }
    55 
    56 class DecreaseThread extends Thread {
    57 
    58     private Sample sample;
    59 
    60     public DecreaseThread(Sample sample) {
    61         this.sample = sample;
    62     }
    63 
    64     @Override
    65     public void run() {
    66         for (int i = 0; i < 20; i++) {
    67             try {
    68                 Thread.sleep((long) Math.random() * 1000);
    69             } catch (Exception e) {
    70                 e.printStackTrace();
    71             }
    72 
    73             sample.decrease();
    74         }
    75     }
    76 }
    77 
    78 class IncreaseThread extends Thread {
    79 
    80     private Sample sample;
    81 
    82     public IncreaseThread(Sample sample) {
    83         this.sample = sample;
    84     }
    85 
    86     @Override
    87     public void run() {
    88         for (int i = 0; i < 20; i++) {
    89             try {
    90                 Thread.sleep((long) Math.random() * 1000);
    91             } catch (Exception e) {
    92                 e.printStackTrace();
    93             }
    94 
    95             sample.increase();
    96         }
    97     }
    98 }

    这里把if判断改成了while循环,因为wait方法之后,应该是需要重复判断一次i的情况的,这样就不会出现数字不对的情况了

    这里有一条基本原则:

    永远在while循环里而不是if语句下使用wait。这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知

  • 相关阅读:
    如何在CentOS系统中安装字体 51CTO.COM
    C++检查输入数据类型? 知乎
    义乌市爱因宝母婴用品有限公司_公司简介
    硬盘对拷必备 AGE USB/eSATA对拷机现卖场!_青岛行情中关村在线
    Download: Microsoft SQL Server Management Studio Express Microsoft Download Center Download Details
    今晚看啥
    nano接收器
    12306订票助手 (版本 3.5.0)
    Microsoft® SQL Server® 2008 Management Studio Express
    有线键盘和鼠标确实应该退出历史舞台了
  • 原文地址:https://www.cnblogs.com/billmiao/p/9872208.html
Copyright © 2020-2023  润新知