• 关于线程等待、线程唤醒方法的引入


    public final void wait()
                    throws InterruptedException  线程等待


    public final void notify()    线程唤醒
      1 public class Student {
      2     private String name;
      3     private int age;
      4 
      5     public Student(String name, int age) {
      6         super();
      7         this.name = name;
      8         this.age = age;
      9     }
     10 
     11     public Student() {
     12 
     13     }
     14 
     15     public int getAge() {
     16         return age;
     17     }
     18 
     19     public void setAge(int age) {
     20         this.age = age;
     21     }
     22 
     23     public String getName() {
     24         return name;
     25     }
     26 
     27     public void setName(String name) {
     28         this.name = name;
     29     }
     30 
     31     @Override
     32     public String toString() {
     33         return "Student [name=" + name + ", age=" + age + "]";
     34     }
     35 
     36 }
     37 
     38 /**
     39  * 生产学生的类
     40  * 
     41  * @author Administrator
     42  *
     43  */
     44 public class SetStudent implements Runnable {
     45     private Student student;
     46 
     47 //    可以通过构造方法确定操作的是同一个学生
     48     public SetStudent(Student student) {
     49         this.student = student;
     50     }
     51 
     52 //    重写的run方法,让他调用生产学生的方法
     53     @Override
     54     public void run() {
     55         createStudent();
     56     }
     57 
     58 //  生产学生”张三“
     59     public void createStudent() {
     60         while (true) {
     61             student.setName("张三");
     62             student.setAge(11);
     63         }
     64     }
     65 
     66 }
     67 
     68 
     69 /**
     70  * 消费学生的类:输出学生
     71  * 
     72  * @author Administrator
     73  *
     74  */
     75 public class GetStudent implements Runnable {
     76     private Student student;
     77 
     78     @Override
     79     public void run() {
     80         getStudent();
     81 
     82     }
     83 
     84     public GetStudent(Student student) {
     85         this.student = student;
     86     }
     87 
     88 //   输出学生
     89     public void getStudent() {
     90         while (true) {
     91             System.out.println(student);
     92         }
     93 
     94     }
     95 }
     96 
     97 
     98 public class StudentTest {
     99     public static void main(String[] args) {
    100 //        主方法创建一个学生,并通过参数传递赋给生产者和消费者,引用变量,传递同一个学生的引用地址,保证操作的都是一个对象
    101         Student student = new Student();
    102         SetStudent setStu = new SetStudent(student);
    103         GetStudent getStu = new GetStudent(student);
    104 //        创建线程
    105         Thread setStudent = new Thread(setStu);
    106         Thread getStudent = new Thread(getStu);
    107 //        开启线程
    108         setStudent.start();
    109         getStudent.start();
    110     }
    111 }
    112 //执行结果:
    113 //Student [name=张三, age=11]
    114 //Student [name=张三, age=11]
    115 //Student [name=张三, age=11]
    116 //Student [name=张三, age=11]
    117 //Student [name=张三, age=11]
    118 //Student [name=张三, age=11]
    119 //Student [name=张三, age=11]
    120 //Student [name=张三, age=11]
    121 //Student [name=张三, age=11]
    122 //Student [name=张三, age=11]
    123 //Student [name=张三, age=11]
    124 //Student [name=张三, age=11]
    125 //Student [name=张三, age=11]
    126 //Student [name=张三, age=11]
    127 //Student [name=张三, age=11]
    128 //Student [name=张三, age=11]
    129 /**
    130  * 这里可以看到生产者和消费者使用的对象都是同一个,但是,如果生产者生产的是两个人,张三和大黄蜂呢?
    131  */
     1 /**
     2  * 生产学生的类
     3  * 
     4  * @author Administrator
     5  *
     6  */
     7 public class SetStudent implements Runnable {
     8     private Student student;
     9     private int index;
    10 
    11 //    可以通过构造方法确定操作的是同一个学生
    12     public SetStudent(Student student) {
    13         this.student = student;
    14     }
    15 
    16 //    重写的run方法,让他调用生产学生的方法
    17     @Override
    18     public void run() {
    19         createStudent();
    20     }
    21 
    22 //  生产学生”张三“
    23     public void createStudent() {
    24         while (true) {
    25             if (index % 2 == 0) {
    26                 student.setName("张三");
    27                 student.setAge(11);
    28             } else {
    29                 student.setName("大黄蜂");
    30                 student.setAge(30);
    31             }
    32             index++; // 当为奇数时生产大黄蜂,当为偶数时生产张三
    33         }
    34     }
    35 
    36 }
    37 
    38 
    39 public class StudentTest {
    40     public static void main(String[] args) {
    41 //        主方法创建一个学生,并通过参数传递赋给生产者和消费者,引用变量,传递同一个学生的引用地址,保证操作的都是一个对象
    42         Student student = new Student();
    43         SetStudent setStu = new SetStudent(student);
    44         GetStudent getStu = new GetStudent(student);
    45 //        创建线程
    46         Thread setStudent = new Thread(setStu);
    47         Thread getStudent = new Thread(getStu);
    48 //        开启线程
    49         setStudent.start();
    50         getStudent.start();
    51     }
    52 }
    53 //执行结果:
    54 //Student [name=大黄蜂, age=11]
    55 //Student [name=大黄蜂, age=30]
    56 //Student [name=大黄蜂, age=11]
    57 //Student [name=大黄蜂, age=11]
    58 //Student [name=大黄蜂, age=11]
    59 //Student [name=张三, age=11]
    60 //Student [name=大黄蜂, age=11]
    61 //Student [name=大黄蜂, age=11]
    62 //Student [name=大黄蜂, age=30]
    63 //Student [name=大黄蜂, age=30]
    64 //Student [name=张三, age=30]
    65 //Student [name=张三, age=11]
    66 //Student [name=大黄蜂, age=11]
    67 //Student [name=张三, age=11]
    68 //Student [name=大黄蜂, age=30]
    69 //Student [name=张三, age=11]
    70 //Student [name=大黄蜂, age=11]
    71 /**
    72  * 这里虽然生产出来了不同的对象,但是年龄和名字好像不对号
    73  * 解释:在同一个时间点,CPU只能执行一条指令,在生产者抢到CPU给名字赋值张三时,
    74  * 消费者抢到了Cpu要输出,所以年龄并没赋值,用的是之前的年龄
    75  * 解决办法:加一个同步代码块
    76  */

    在生产学生处和消费学生方法增加同步代码块

    //  生产学生”张三“
        public void createStudent() {
            while (true) {
                synchronized (student) {
                    if (index % 2 == 0) {
                        student.setName("张三");
                        student.setAge(11);
                    } else {
                        student.setName("大黄蜂");
                        student.setAge(30);
                    }
                    index++; // 当为奇数时生产大黄蜂,当为偶数时生产张三
                }
            }
        }
    
    //   输出学生
        public void getStudent() {
            while (true) {
                synchronized (student) {
                    System.out.println(student);
                    try {
                        Thread.sleep(100); // 输出太快了,模拟网络,让输出看起来均衡
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
            }
    
        }
    
    public class StudentTest {
        public static void main(String[] args) {
    //        主方法创建一个学生,并通过参数传递赋给生产者和消费者,引用变量,传递同一个学生的引用地址,保证操作的都是一个对象
            Student student = new Student();
            SetStudent setStu = new SetStudent(student);
            GetStudent getStu = new GetStudent(student);
    //        创建线程
            Thread setStudent = new Thread(setStu);
            Thread getStudent = new Thread(getStu);
    //        开启线程
            setStudent.start();
            getStudent.start();
        }
    }
    //执行结果:
    //Student [name=null, age=0]
    //Student [name=null, age=0]
    //Student [name=null, age=0]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=张三, age=11]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    //Student [name=大黄蜂, age=30]
    /**
     * 年龄对号,但是在生产者中添加了index,就是为了让奇数偶数一个一个分别输出,但是情况不对
     * 解释:虽然加了同步代码块,但是两个线程CPU的抢占时间是随机的,消费者一直抢占CPU就一直输出,但是生产者还没有生产出来,消费者不该输出
     * 解决办法:使用线程等待:
     *     生产者先生产,消费者再消费
        生产者没有生产,消费者等待
        生产者已经生产,消费者没有消费,生产者等待
     */

     完整

      1 public class Student {
      2     private String name;
      3     private int age;
      4     boolean flag = true; // 当为真时,生产者才生产
      5 
      6     public Student(String name, int age) {
      7         super();
      8         this.name = name;
      9         this.age = age;
     10     }
     11 
     12     public Student() {
     13 
     14     }
     15 
     16     public int getAge() {
     17         return age;
     18     }
     19 
     20     public void setAge(int age) {
     21         this.age = age;
     22     }
     23 
     24     public String getName() {
     25         return name;
     26     }
     27 
     28     public void setName(String name) {
     29         this.name = name;
     30     }
     31 
     32     @Override
     33     public String toString() {
     34         return "Student [name=" + name + ", age=" + age + "]";
     35     }
     36 
     37 }
     38 
     39 
     40 /**
     41  * 生产学生的类
     42  * 
     43  * @author Administrator
     44  *
     45  */
     46 public class SetStudent implements Runnable {
     47     private Student student;
     48     private int index;
     49 
     50 //    可以通过构造方法确定操作的是同一个学生
     51     public SetStudent(Student student) {
     52         this.student = student;
     53     }
     54 
     55 //    重写的run方法,让他调用生产学生的方法
     56     @Override
     57     public void run() {
     58         createStudent();
     59     }
     60 
     61 //  生产学生”张三“
     62     public void createStudent() {
     63         while (true) {
     64             synchronized (student) {
     65                 if (student.flag) { // 当flag为真时,已经生产,等待消费者消费,归还锁,当被唤醒就从这里开始
     66                     try {
     67                         student.wait();
     68                     } catch (InterruptedException e) {
     69                         e.printStackTrace();
     70                     }
     71                 }
     72                 if (index % 2 == 0) {
     73                     student.setName("张三");
     74                     student.setAge(11);
     75                 } else {
     76                     student.setName("大黄蜂");
     77                     student.setAge(30);
     78                 }
     79 
     80                 index++; // 当为奇数时生产大黄蜂,当为偶数时生产张三
     81                 student.flag = true; // 唤醒生产者,让他抢CPU
     82                 student.notify();
     83 //                
     84             }
     85         }
     86     }
     87 
     88 }
     89 
     90 
     91 /**
     92  * 消费学生的类:输出学生
     93  * 
     94  * @author Administrator
     95  *
     96  */
     97 public class GetStudent implements Runnable {
     98     private Student student;
     99 
    100     @Override
    101     public void run() {
    102         getStudent();
    103 
    104     }
    105 
    106     public GetStudent(Student student) {
    107         this.student = student;
    108     }
    109 
    110 //   输出学生
    111     public void getStudent() {
    112         while (true) {
    113             synchronized (student) {
    114                 // 等于true时,生产者已经生产,此时消费者才可以消费,反之,当是false的时候,就应该等待生产者生产
    115                 if (!student.flag) {
    116                     try {
    117                         student.wait();
    118                     } catch (InterruptedException e) {
    119                         e.printStackTrace();
    120                     }
    121                 }
    122                 System.out.println(student);
    123                 student.flag = false; // 改变参数,并且唤醒消费者线程,让他抢CPU
    124                 student.notify();
    125             }
    126 
    127         }
    128 
    129     }
    130 }
    131 
    132 public class StudentTest {
    133     public static void main(String[] args) {
    134 //        主方法创建一个学生,并通过参数传递赋给生产者和消费者,引用变量,传递同一个学生的引用地址,保证操作的都是一个对象
    135         Student student = new Student();
    136         SetStudent setStu = new SetStudent(student);
    137         GetStudent getStu = new GetStudent(student);
    138 //        创建线程
    139         Thread setStudent = new Thread(setStu);
    140         Thread getStudent = new Thread(getStu);
    141 //        开启线程
    142         setStudent.start();
    143         getStudent.start();
    144     }
    145 }
    146 //执行结果:
    147 //Student [name=张三, age=11]
    148 //Student [name=大黄蜂, age=30]
    149 //Student [name=张三, age=11]
    150 //Student [name=大黄蜂, age=30]
    151 //Student [name=张三, age=11]
    152 //Student [name=大黄蜂, age=30]
    153 //Student [name=张三, age=11]
    154 //Student [name=大黄蜂, age=30]
    155 //Student [name=张三, age=11]
     
  • 相关阅读:
    Spring Boot 2.0 + zipkin 分布式跟踪系统快速入门
    在线yaml转Properties
    Spring Boot 配置优先级顺序
    集群服务器下使用SpringBoot @Scheduled注解定时任务
    spring-boot项目在eclipse中指定配置文件启动
    org.hibernate.TransientObjectException异常
    Servlet、ServletConfig、ServletContext深入学习
    Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别、SSH线程安全问题
    nested exception is com.svorx.core.dao.PersistenceException
    yui压缩JS和CSS文件
  • 原文地址:https://www.cnblogs.com/19322li/p/10700939.html
Copyright © 2020-2023  润新知