一、本案例设计到的知识点
(1)Object的notify(),notifyAll(),wait()等方法
(2)Thread的sleep(),interrupt()。
(3)如何终止线程。
(4)如何控制多个线程之间按顺序执行。
二、一个电梯的上下运送人员的案例
引用生活中的一个情景,(先从最简单的处理方式出发,以后再出后续研究版本):
已知:一楼是服务大厅,顶楼是一个餐厅(食堂),顶楼有一群人等待坐电梯下到一楼,一楼有部分人再等待坐电梯去顶楼。限制的条件有:只有一部电梯,每次电梯只能运载一个人。
那么如何实现这种场景呢?
(以后再放开条件研究:多部电梯,多个人,去不同楼层的实现方法,此处先从最简单的入手)
那么继续分析:
把当前的场景按照面向对象的思想来抽象一下:
创建如下类:Personnel 工作人员类,Elevator 电梯类,DownThread 电梯下送工作线程,UpThread 电梯上送工作线程, 以及一个测试类ThreadTest
具体代码如下:
Personnel 工作人员类
1 package com.jason.models; 2 /** 3 * 多线程学习:·分析 4 * @function 工作人员类 5 * @author 小风微凉 6 * @time 2018-4-26 下午1:01:53 7 */ 8 public class Personnel { 9 private String name; 10 public Personnel(String name){ 11 this.name=name; 12 } 13 @Override 14 public String toString() { 15 return this.name; 16 } 17 }
Elevator 电梯类
1 package com.jason.models; 2 import java.util.ArrayList; 3 import java.util.List; 4 /** 5 * 多线程学习:生产者消费者模型·分析 6 * @function 电梯类 7 * @author 小风微凉 8 * @time 2018-4-26 下午1:00:58 9 */ 10 public class Elevator{ 11 //电梯编号:以后扩展 12 private String eleNo; 13 //电梯每次最大的载重人数为:15人 14 private final int MAX_PERSON_LIMIT=15; 15 //构造器 16 public Elevator(String eleNo){ 17 this.eleNo=eleNo; 18 } 19 /** 20 * //向上运送人员 21 * @param list 上限运载的人数 22 * @param exitFlag true 终止线程 false 继续 23 * @return 返回成功运载的人数 24 */ 25 public synchronized void upCarry(List<Personnel> list,boolean exitFlag){ 26 //当前电梯的乘坐人数 27 int currCount=list.size(); 28 if(currCount==0){//没有人员乘坐 29 System.out.println("(up)当前电梯没有人员乘坐,可以抢夺电梯的使用权!"); 30 this.notifyAll();//唤醒楼上-楼下的人争抢按电梯 31 } 32 if(currCount>MAX_PERSON_LIMIT){//人数超载 33 System.out.println("(up)警告!人数超过运载上限:"+currCount+","+MAX_PERSON_LIMIT+"人,电梯等候运行!"); 34 try { 35 Thread.sleep(1000);//带着电梯对象锁,休眠一会 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 Thread.currentThread().interrupt();//中断线程 39 } 40 } 41 if(currCount>0 && currCount<=MAX_PERSON_LIMIT){//正常运载范围 42 System.out.println(Thread.currentThread().getName()+":向上运载了第:"+list.size()+"位乘客。抵达楼顶食堂"); 43 this.notifyAll();//只是为了唤醒其他线程,并释放当前线程(和下面wait()有重复) 44 try { 45 this.wait();//此时电梯到达楼上,当前线程进入等待池 46 } catch (InterruptedException e) { 47 e.printStackTrace(); 48 Thread.currentThread().interrupt();//中断线程 49 } 50 System.out.println("---------------[继续UP]后续代码继续执行-------------"); 51 } 52 if(exitFlag){ 53 //终止当前线程,唤醒其他线程 54 this.notifyAll(); 55 } 56 } 57 /** 58 * //向下运送人员 59 * @param list 上限运载的人数 60 * @return 返回成功运载的人数 61 */ 62 public synchronized void downCarry(List<Personnel> list,boolean exitFlag){ 63 //当前电梯的乘坐人数 64 int currCount=list.size(); 65 if(currCount==0){//没有人员乘坐 66 System.out.println("(downn)当前电梯没有人员乘坐,可以抢夺电梯的使用权!"); 67 this.notifyAll();//唤醒楼上-楼下的人争抢按电梯 68 } 69 if(currCount>MAX_PERSON_LIMIT){//人数超载 70 System.out.println("(downn)警告!人数超过运载上限:"+currCount+","+MAX_PERSON_LIMIT+"人,电梯等候运行!"); 71 try { 72 Thread.sleep(1000);//带着电梯对象锁,休眠一会 73 } catch (InterruptedException e) { 74 e.printStackTrace(); 75 Thread.currentThread().interrupt();//中断线程 76 } 77 } 78 if(currCount>0 && currCount<=MAX_PERSON_LIMIT){//正常运载范围 79 System.out.println(Thread.currentThread().getName()+":向下运载了第:"+list.size()+"位乘客。抵达一楼大厅"); 80 this.notifyAll(); 81 try { 82 this.wait();//此时电梯到达楼下,下送线程进入等待池,上送线程可以拿到电梯使用权 83 } catch (InterruptedException e) { 84 e.printStackTrace(); 85 Thread.currentThread().interrupt();//中断线程 86 } 87 System.out.println("---------------[继续DOWN]后续代码继续执行-------------"); 88 } 89 if(exitFlag){ 90 //终止当前线程,唤醒其他线程 91 this.notifyAll(); 92 } 93 } 94 }
UpThread 电梯上送工作线程
1 /** 2 * 上送工作线程 3 * @function 4 * @author 小风微凉 5 * @time 2018-4-26 下午1:48:44 6 */ 7 class UpThread implements Runnable{ 8 private Elevator elev; 9 List<Personnel> list; 10 public UpThread(Elevator elev,List<Personnel> list){ 11 this.elev=elev; 12 this.list=list; 13 } 14 public void run() { 15 for(int i=1;i<=list.size();i++){ 16 if(i==list.size()){ 17 elev.upCarry(list.subList(0, i),true); 18 }else{ 19 elev.upCarry(list.subList(0, i), false); 20 } 21 } 22 System.out.println("******[UP线程-END]******************"); 23 } 24 }
DownThread 电梯下送工作线程
/** * 下送工作线程 * @function * @author 小风微凉 * @time 2018-4-26 下午1:48:44 */ class DownThread implements Runnable{ private Elevator elev; List<Personnel> list; public DownThread(Elevator elev,List<Personnel> list){ this.elev=elev; this.list=list; } public void run() { for(int i=1;i<=list.size();i++){ if(i==list.size()){ elev.downCarry(list.subList(0, i),true); }else{ elev.downCarry(list.subList(0, i), false); } } System.out.println("******[DOWN线程-END]******************"); } }
一个测试类ThreadTest
1 package com.jason.models; 2 3 import java.util.ArrayList; 4 import java.util.Arrays; 5 import java.util.List; 6 7 public class ThreadTest extends Thread{ 8 /** 9 * @param args 10 */ 11 public static void main(String[] args) { 12 //假设楼上:20人在等待电梯 13 List<Personnel> topList=new ArrayList<Personnel>(); 14 for(int i=1;i<=20;i++){ 15 topList.add(new Personnel("TOP"+i+"号")); 16 } 17 //假设楼下:30人在等待电梯 18 List<Personnel> bottomList=new ArrayList<Personnel>(); 19 for(int i=1;i<=30;i++){ 20 bottomList.add(new Personnel("BOTTOM"+i+"号")); 21 } 22 //创建电梯对象 23 Elevator elev=new Elevator("1号电梯"); 24 //2种工作线程,随即运载工作人员 25 new Thread(new UpThread(elev,topList),"UP").start(); 26 new Thread(new DownThread(elev,bottomList),"DOWN").start(); 27 } 28 }
运行结果:
UP:向上运载了第:1位乘客。抵达楼顶食堂 DOWN:向下运载了第:1位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:2位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:2位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:3位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:3位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:4位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:4位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:5位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:5位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:6位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:6位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:7位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:7位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:8位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:8位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:9位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:9位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:10位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:10位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:11位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:11位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:12位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:12位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:13位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:13位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:14位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:14位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- UP:向上运载了第:15位乘客。抵达楼顶食堂 ---------------[继续DOWN]后续代码继续执行------------- DOWN:向下运载了第:15位乘客。抵达一楼大厅 ---------------[继续UP]后续代码继续执行------------- (up)警告!人数超过运载上限:16,15人,电梯等候运行! (up)警告!人数超过运载上限:17,15人,电梯等候运行! (up)警告!人数超过运载上限:18,15人,电梯等候运行! (up)警告!人数超过运载上限:19,15人,电梯等候运行! (up)警告!人数超过运载上限:20,15人,电梯等候运行! ---------------[继续DOWN]后续代码继续执行------------- ******[UP线程-END]****************** (downn)警告!人数超过运载上限:16,15人,电梯等候运行! (downn)警告!人数超过运载上限:17,15人,电梯等候运行! (downn)警告!人数超过运载上限:18,15人,电梯等候运行! (downn)警告!人数超过运载上限:19,15人,电梯等候运行! (downn)警告!人数超过运载上限:20,15人,电梯等候运行! (downn)警告!人数超过运载上限:21,15人,电梯等候运行! (downn)警告!人数超过运载上限:22,15人,电梯等候运行! (downn)警告!人数超过运载上限:23,15人,电梯等候运行! (downn)警告!人数超过运载上限:24,15人,电梯等候运行! (downn)警告!人数超过运载上限:25,15人,电梯等候运行! (downn)警告!人数超过运载上限:26,15人,电梯等候运行! (downn)警告!人数超过运载上限:27,15人,电梯等候运行! (downn)警告!人数超过运载上限:28,15人,电梯等候运行! (downn)警告!人数超过运载上限:29,15人,电梯等候运行! (downn)警告!人数超过运载上限:30,15人,电梯等候运行! ******[DOWN线程-END]******************
运行结果的说明:
(1)程序运行,UP线程和DOWN线程第一时间开始抢夺电梯的使用权。
(2)UP线程和DOWN线程开始按顺序,一次UP,紧接着一次DOWN 交替(等待-唤醒)的轮转。
(3)当其中一个线程结束后,主动唤醒另外一个线程继续执行。
好像逻辑蛮简单的,我酝酿下,再出下一个版本吧~