线程八大基础核心五(线程相关方法一)
在java多线程并发编程中,有八大基础核心。考考你:
看看都有哪八大基础核心呢?它们分别是:
1.创建线程的方式
2.线程启动
3.线程停止
4.线程生命周期
5.线程相关的方法
6.线程相关的属性
7.线程异常处理
8.线程安全
今天我们从第五个基础核心开始:线程相关方法
#前情回顾
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方法的作用吗?
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 }
执行结果:
#考考你答案 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:占有锁对象线程,释放锁并退出执行,线程生命周期结束
我们唯一能够控制的是自己的脾气和努力