线程八大基础核心五(线程相关方法一)

1.引子

在java多线程并发编程中,有八大基础核心。考考你:
看看都有哪八大基础核心呢?它们分别是:
1.创建线程的方式
2.线程启动
3.线程停止
4.线程生命周期
5.线程相关的方法
6.线程相关的属性
7.线程异常处理
8.线程安全

今天我们从第五个基础核心开始:线程相关方法

2.考考你

#前情回顾
1.在java编程语言中,与线程相关的方法主要有:
1.1.Object.wait/Object.notify/Object/notifyAll
1.2.Thread.sleep/Thread.join/Thread.yield
2.需要把各个方法的作用和使用场景说清楚,需要用两篇文章进行分享

#考考你
1.你知道wait/notify/notifyAll方法的作用吗?
2.你知道notify与notifyAll方法的区别吗?
3.你知道sleep方法的作用吗?
4.你知道wait与sleep方法的区别吗?
5.你知道join方法的作用吗?
6.你知道yield方法的作用吗?

3.案例:wait/notify/notifyAll

方法简述:

wait:释放线程拥有的当前锁对象,让线程进入WAITING状态

notify:唤醒当前锁对象等待池(WaitSet)中,某一个线程

notifyAll:唤醒当前锁对象等待池(WaitSet)中,所有线程

业务描述:

1.通过wait与notify(notifyAll)实现线程协同,实现经典的生产者消费者模式

2.编写生产者,向队列中生产数据,如果队列满,生产者进行等待,并唤醒消费者进行消费

3.编写消费者,从队列中消费数据,如果队列空,消费者进行等待,并唤醒生产者进行生产

4.在主类main方法中,创建两个生产者线程进行生产

5.在主类main方法中,创建一个消费者线程进行消费

生产者:

 1 /**
 2  * 生产者
 3  */
 4 class Producer implements Runnable{
 5 
 6     public void run() {
 7         while(true){
 8             synchronized (ProducerConsumerDemo.LOCK){
 9                 // 检查队列是否满,推荐用while而不是if
10                 while(ProducerConsumerDemo.QUEUE.size() ==
11                         ProducerConsumerDemo.CAPACITY){
12                     // 如果队列满,则等待消费者消费
13                     try {
14                         System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
15                                 Thread.currentThread().getName() + "】正在等待消费者消费.");
16                         ProducerConsumerDemo.LOCK.wait();
17                     } catch (InterruptedException e) {
18                         e.printStackTrace();
19                     }
20                 }
21 
22                 // 如果队列不满,则正常生产
23                 ProducerConsumerDemo.QUEUE.add(1);
24                 System.out.println("线程【" + Thread.currentThread().getName() +
25                         "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
26 
27                 // 唤醒消费者
28                 ProducerConsumerDemo.LOCK.notifyAll();
29             }
30         }
31     }
32 }

消费者:

 1 /**
 2  * 消费者
 3  */
 4 class Consumer implements Runnable{
 5 
 6     public void run() {
 7         while(true){
 8             synchronized (ProducerConsumerDemo.LOCK){
 9                 // 检查队列是否空,推荐用while而不是if
10                 while(ProducerConsumerDemo.QUEUE.isEmpty()){
11                     // 如果队列空,则等待生产者生产
12                     try {
13                         System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
14                                 Thread.currentThread().getName() + "】正在等待生产者生产.");
15                         ProducerConsumerDemo.LOCK.wait();
16                     } catch (InterruptedException e) {
17                         e.printStackTrace();
18                     }
19                 }
20 
21                 // 如果队列不空,则正常消费
22                 ProducerConsumerDemo.QUEUE.remove(0);
23                 System.out.println("线程【" + Thread.currentThread().getName() +
24                         "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
25 
26                 // 唤醒生产者
27                 ProducerConsumerDemo.LOCK.notifyAll();
28             }
29         }
30     }
31 }

完整代码:

 1 package com.anan.thread.threadmethod;
 2 
 3 import java.util.ArrayList;
 4 
 5 /**
 6  * 生产者消费者模型:wait与notify(notifyAll)
 7  */
 8 public class ProducerConsumerDemo {
 9 
10     // 定义公共资源:队列容量、队列
11     public final static Integer CAPACITY = 6;
12     public final static ArrayList<Integer> QUEUE = new ArrayList<Integer>(CAPACITY);
13 
14     // 定义锁对象
15     public final static Object LOCK = new Object();
16 
17     public static void main(String[] args) {
18 
19         // 创建两个生产者线程
20         Runnable r1 = new Producer();
21         Thread producer0 = new Thread(r1,"producer-0");
22         producer0.start();
23 
24         Thread producer1 = new Thread(r1,"producer-1");
25         producer1.start();
26 
27         // 创建消费者线程
28         Runnable r2 = new Consumer();
29         Thread consumer1 = new Thread(r2,"consumer-0");
30         consumer1.start();
31 
32     }
33 }
34 
35 /**
36  * 生产者
37  */
38 class Producer implements Runnable{
39 
40     public void run() {
41         while(true){
42             synchronized (ProducerConsumerDemo.LOCK){
43                 // 检查队列是否满,推荐用while而不是if
44                 while(ProducerConsumerDemo.QUEUE.size() ==
45                         ProducerConsumerDemo.CAPACITY){
46                     // 如果队列满,则等待消费者消费
47                     try {
48                         System.out.println("队列满size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
49                                 Thread.currentThread().getName() + "】正在等待消费者消费.");
50                         ProducerConsumerDemo.LOCK.wait();
51                     } catch (InterruptedException e) {
52                         e.printStackTrace();
53                     }
54                 }
55 
56                 // 如果队列不满,则正常生产
57                 ProducerConsumerDemo.QUEUE.add(1);
58                 System.out.println("线程【" + Thread.currentThread().getName() +
59                         "】生产了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
60 
61                 // 唤醒消费者
62                 ProducerConsumerDemo.LOCK.notifyAll();
63             }
64         }
65     }
66 }
67 
68 /**
69  * 消费者
70  */
71 class Consumer implements Runnable{
72 
73     public void run() {
74         while(true){
75             synchronized (ProducerConsumerDemo.LOCK){
76                 // 检查队列是否空,推荐用while而不是if
77                 while(ProducerConsumerDemo.QUEUE.isEmpty()){
78                     // 如果队列空,则等待生产者生产
79                     try {
80                         System.out.println("队列空size:" +ProducerConsumerDemo.QUEUE.size()+ ",线程【" +
81                                 Thread.currentThread().getName() + "】正在等待生产者生产.");
82                         ProducerConsumerDemo.LOCK.wait();
83                     } catch (InterruptedException e) {
84                         e.printStackTrace();
85                     }
86                 }
87 
88                 // 如果队列不空,则正常消费
89                 ProducerConsumerDemo.QUEUE.remove(0);
90                 System.out.println("线程【" + Thread.currentThread().getName() +
91                         "】消费了数据.当前队列size:" + ProducerConsumerDemo.QUEUE.size());
92 
93                 // 唤醒生产者
94                 ProducerConsumerDemo.LOCK.notifyAll();
95             }
96         }
97     }
98 }

执行结果:

 

 

4.讨论分享

#考考你答案
1.你知道wait/notify/notifyAll方法的作用吗?
 1.1.wait/notify/notifyAll都是Object中的方法
 1.2.通过等待与唤醒,实现线程之间的协同
 1.3.wait方法会释放当前锁对象,让线程进入WAITING状态
 1.4.notify方法用于:
  1.4.1.唤醒当前锁对象等待池(WaitSet)中,正在等待
   当前锁对象的某一个线程
  1.4.2.让该线程进入RUNNABLE状态,并移入锁池(EntrySet)中,
  重新竞争锁对象
 1.5.notifyAll方法用于:
  1.5.1.唤醒当前锁对象等待池(WaitSet)中,正在等待
   当前锁对象的所有线程
  1.5.2.让等待当前锁对象的所有线程,进入RUNNABLE状态,并
   移入锁池(EntrySet)中,重新竞争锁对象
  
2.你知道notify与notifyAll方法的区别吗?
 2.1.通过以上1.4点、1.5点已经说明了notify
 与notifyAll的区别
 2.2.这里可能有朋友不明白锁池(EntrySet),与
 等待池(WaitSet)的概念。我们通过一个图进行说明:
  
#流程文字描述:
1.锁池(EntrySet):代表正在等待同一锁对象的线程集合,线程进入BLOCKED状态
2.拥有者(Owner):代表已经获取到锁对象的线程
3.等待池(WaitSet):代表已经进入WAITING状态,等待被唤醒的线程集合
4.流程描述:
  4.1.enter:线程准备获取锁对象,此时锁被其它线程占有,线程进入EntrySet
  4.2.acquire:当其它线程释放锁对象,EntrySet中的某个线程获取占有锁对象
  4.3.release:占有锁对象线程,通过wait方式释放锁对象,进入WaitSet中,等待被唤醒
  4.4.acquire:当有其它线程,通过notify/notifyAll方法唤醒WaitSet中线程,线程将重新进入EntrySet,重新竞争获取锁对象
  4.5.release and exit:占有锁对象线程,释放锁并退出执行,线程生命周期结束 

 

posted @ 2020-02-08 10:19  小杨【0和1】  阅读(353)  评论(0编辑  收藏  举报