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

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]

 

 
posted @ 2019-04-13 14:04  我差两天十八岁  阅读(448)  评论(0编辑  收藏  举报