Java多线程(六)线程通信

线程通信的例子

使用两个线程打印 1-100。线程1, 线程2 交替打印 
 涉及到的三个方法:

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
  • notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。

说明:

  • wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
  • wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常
  • wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

面试题:sleep() 和 wait()的异同?
1. 相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2. 不同点:1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()
2. 调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
3. 关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。(这里锁即同步监视器)

 1 class Number implements Runnable{
 2     private int number = 1;
 3     private Object obj = new Object();
 4     @Override
 5     public void run() {
 6 
 7         while(true){
 8         //当线程1进入同步监视器,进行输出后,通过wait方法被阻塞并释放同步监视器。此时线程2进入
 9         //线程2进入同步监视器,首先通过notify方法使线程1由阻塞变为就绪,但此时同步监视器由线程2操作,所以线程1保持就绪直至线程2释放资源
10             synchronized (obj) {
11 
12                 obj.notify();
13 
14                 if(number <= 100){
15 
16                     try {
17                         Thread.sleep(10);
18                     } catch (InterruptedException e) {
19                         e.printStackTrace();
20                     }
21 
22                     System.out.println(Thread.currentThread().getName() + ":" + number);
23                     number++;
24 
25                     try {
26                         //使得调用如下wait()方法的线程进入阻塞状态
27                         obj.wait();
28                     } catch (InterruptedException e) {
29                         e.printStackTrace();
30                     }
31 
32                 }else{
33                     break;
34                 }
35             }
36 
37         }
38 
39     }
40 }

生产者/消费者问题

经典的线程同步问题,这里需要线程通信的方法来解决该问题。

生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。

分析:
1. 是否是多线程问题?是,生产者线程,消费者线程
2. 是否有共享数据?是,店员(或产品)
3. 如何解决线程的安全问题?同步机制,有三种方法
4. 是否涉及线程的通信?是

  1 class Clerk{
  2 
  3     private int productCount = 0;
  4     //生产产品
  5     public synchronized void produceProduct() {
  6 
  7         if(productCount < 20){
  8             productCount++;
  9             System.out.println(Thread.currentThread().getName() + ":开始生产第" + productCount + "个产品");
 10 
 11             notify();
 12 
 13         }else{
 14             //等待
 15             try {
 16                 wait();
 17             } catch (InterruptedException e) {
 18                 e.printStackTrace();
 19             }
 20         }
 21     }
 22     //消费产品
 23     public synchronized void consumeProduct() {
 24         if(productCount > 0){
 25             System.out.println(Thread.currentThread().getName() + ":开始消费第" + productCount + "个产品");
 26             productCount--;
 27 
 28             notify();
 29         }else{
 30             //等待
 31             try {
 32                 wait();
 33             } catch (InterruptedException e) {
 34                 e.printStackTrace();
 35             }
 36         }
 37 
 38     }
 39 }
 40 
 41 class Producer extends Thread{//生产者
 42 
 43     private Clerk clerk;
 44 
 45     public Producer(Clerk clerk) {
 46         this.clerk = clerk;
 47     }
 48 
 49     @Override
 50     public void run() {
 51         System.out.println(getName() + ":开始生产产品.....");
 52 
 53         while(true){
 54 
 55             try {
 56                 Thread.sleep(10);
 57             } catch (InterruptedException e) {
 58                 e.printStackTrace();
 59             }
 60 
 61             clerk.produceProduct();
 62         }
 63 
 64     }
 65 }
 66 
 67 class Consumer extends Thread{//消费者
 68     private Clerk clerk;
 69 
 70     public Consumer(Clerk clerk) {
 71         this.clerk = clerk;
 72     }
 73 
 74     @Override
 75     public void run() {
 76         System.out.println(getName() + ":开始消费产品.....");
 77 
 78         while(true){
 79 
 80             try {
 81                 Thread.sleep(20);
 82             } catch (InterruptedException e) {
 83                 e.printStackTrace();
 84             }
 85 
 86             clerk.consumeProduct();
 87         }
 88     }
 89 }
 90 
 91 public class ProductTest {
 92 
 93     public static void main(String[] args) {
 94         Clerk clerk = new Clerk();
 95 
 96         Producer p1 = new Producer(clerk);
 97         p1.setName("生产者1");
 98 
 99         Consumer c1 = new Consumer(clerk);
100         c1.setName("消费者1");
101         Consumer c2 = new Consumer(clerk);
102         c2.setName("消费者2");
103 
104         p1.start();
105         c1.start();
106         c2.start();
107 
108     }
109 }

 

posted @ 2021-07-10 16:01  雪之下。  阅读(50)  评论(0)    收藏  举报