1 package day2_4;
2
3 /**
4 * 线程通信:线程1和线程2,轮流交替打印1-100
5 *
6 * 涉及到的三个方法:
7 * wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
8 * notify():一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就唤醒优先级高的那个
9 * notifyAll():一旦执行此方法,就会唤醒所有的被wait的线程
10 *
11 * 说明:
12 * 1.上面三个方法必须使用在同步代码块或者同步方法中
13 * 2.上面三个方法的调用者必须是同步代码块或者同步方法中的同步监视器
14 * 否则会出现IllegalMonitorStateException ---非法监视器异常
15 * 3.上面三个方法是定义在java.lang.Object类中,因为任何类都是Object的子类,所以任何类的对象都可以充当
16 * 同步监视器,并且调动上面三个方法。
17 *
18 * 面试题:sleep() 和 wait() 的异同?
19 * 相同点:一旦执行方法,都可以使当前线程进入阻塞状态
20 * 不同点:1)方法声明的位置不同:sleep()声明在Thread类中,wait()声明在Object类中
21 * 2)调用的要求不同:sleep()可以在任何需要的场景调用,wait()必须在同步代码块或
22 * 同步方法中才能调用
23 * 3)关于是否释放同步监视器(锁):如果两个方法都使用在同步代码块或者同步方法中,sleep()不会释放锁,
24 * 而wait()会释放锁。
25 *
26 *
27 * @Author Tianhao
28 * @create 2021-02-05-21:05
29 */
30
31 class Number implements Runnable{
32 private int number = 1;
33 private Object obj = new Object();
34
35 // //这是原本的打印情况
36 // @Override
37 // public void run() {
38 // while (true) {
39 // //这里加入sleep,是为了更好地看到两个线程交替打印的现象
40 // try {
41 // Thread.sleep(5);
42 // } catch (InterruptedException e) {
43 // e.printStackTrace();
44 // }
45 // synchronized (this) {
46 // if (number <= 100) {
47 // System.out.println(Thread.currentThread().getName() + "打印:" + number);
48 // number++;
49 // } else {
50 // break;
51 // }
52 // }
53 // }
54 // }
55
56 //利用线程通信,实现两个线程轮流交替打印
57 @Override
58 public void run() {
59 while (true) {
60 //当同步监视器是Object对象obj时,wait()、notify()、notifyAll()的调用者也必须是obj
61 //synchronized (obj) {
62 synchronized (this) {
63 //2.notify()唤醒正在wait的线程
64 //obj.notify();
65 notify(); //因为此时同步监视器是this,所以可以省略this.
66 if (number <= 100) {
67 System.out.println(Thread.currentThread().getName() + "打印:" + number);
68 number++;
69 } else {
70 break;
71 }
72 try {
73 //1.线程一旦执行wait(),就会阻塞,同时释放同步监视器
74 //obj.wait();
75 wait(); //因为此时同步监视器是this,所以可以省略this.
76 } catch (InterruptedException e) {
77 e.printStackTrace();
78 }
79 }
80 }
81 }
82 }
83
84 public class CommunityTest {
85 public static void main(String[] args) {
86 Number n = new Number();
87 Thread t1 = new Thread(n);
88 Thread t2 = new Thread(n);
89 t1.setName("线程1");
90 t2.setName("线程2");
91 t1.start();
92 t2.start();
93 }
94 }