一、本案例设计到的知识点

  (1)Object的notify(),notifyAll(),wait()等方法

  (2)Thread的sleep(),interrupt()。

  (3)如何终止线程。

  (4)如何控制多个线程之间按顺序执行。

二、一个电梯的上下运送人员的案例

     引用生活中的一个情景,(先从最简单的处理方式出发,以后再出后续研究版本):

    已知:一楼是服务大厅,顶楼是一个餐厅(食堂),顶楼有一群人等待坐电梯下到一楼,一楼有部分人再等待坐电梯去顶楼。限制的条件有:只有一部电梯,每次电梯只能运载一个人。

    那么如何实现这种场景呢?

    (以后再放开条件研究:多部电梯,多个人,去不同楼层的实现方法,此处先从最简单的入手)  

   那么继续分析:

      把当前的场景按照面向对象的思想来抽象一下:

      创建如下类:Personnel 工作人员类,Elevator  电梯类,DownThread  电梯下送工作线程,UpThread 电梯上送工作线程, 以及一个测试类ThreadTest

  具体代码如下:

  Personnel 工作人员类  

 package com.jason.models;
/**
* 多线程学习:·分析
* @function 工作人员类
* @author 小风微凉
* @time 2018-4-26 下午1:01:53
*/
public class Personnel {
private String name;
public Personnel(String name){
this.name=name;
}
@Override
public String toString() {
return this.name;
}
}

Elevator  电梯类

 package com.jason.models;
import java.util.ArrayList;
import java.util.List;
/**
* 多线程学习:生产者消费者模型·分析
* @function 电梯类
* @author 小风微凉
* @time 2018-4-26 下午1:00:58
*/
public class Elevator{
//电梯编号:以后扩展
private String eleNo;
//电梯每次最大的载重人数为:15人
private final int MAX_PERSON_LIMIT=15;
//构造器
public Elevator(String eleNo){
this.eleNo=eleNo;
}
/**
* //向上运送人员
* @param list 上限运载的人数
* @param exitFlag true 终止线程 false 继续
* @return 返回成功运载的人数
*/
public synchronized void upCarry(List<Personnel> list,boolean exitFlag){
//当前电梯的乘坐人数
int currCount=list.size();
if(currCount==0){//没有人员乘坐
System.out.println("(up)当前电梯没有人员乘坐,可以抢夺电梯的使用权!");
this.notifyAll();//唤醒楼上-楼下的人争抢按电梯
}
if(currCount>MAX_PERSON_LIMIT){//人数超载
System.out.println("(up)警告!人数超过运载上限:"+currCount+","+MAX_PERSON_LIMIT+"人,电梯等候运行!");
try {
Thread.sleep(1000);//带着电梯对象锁,休眠一会
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
}
if(currCount>0 && currCount<=MAX_PERSON_LIMIT){//正常运载范围
System.out.println(Thread.currentThread().getName()+":向上运载了第:"+list.size()+"位乘客。抵达楼顶食堂");
this.notifyAll();//只是为了唤醒其他线程,并释放当前线程(和下面wait()有重复)
try {
this.wait();//此时电梯到达楼上,当前线程进入等待池
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
System.out.println("---------------[继续UP]后续代码继续执行-------------");
}
if(exitFlag){
//终止当前线程,唤醒其他线程
this.notifyAll();
}
}
/**
* //向下运送人员
* @param list 上限运载的人数
* @return 返回成功运载的人数
*/
public synchronized void downCarry(List<Personnel> list,boolean exitFlag){
//当前电梯的乘坐人数
int currCount=list.size();
if(currCount==0){//没有人员乘坐
System.out.println("(downn)当前电梯没有人员乘坐,可以抢夺电梯的使用权!");
this.notifyAll();//唤醒楼上-楼下的人争抢按电梯
}
if(currCount>MAX_PERSON_LIMIT){//人数超载
System.out.println("(downn)警告!人数超过运载上限:"+currCount+","+MAX_PERSON_LIMIT+"人,电梯等候运行!");
try {
Thread.sleep(1000);//带着电梯对象锁,休眠一会
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
}
if(currCount>0 && currCount<=MAX_PERSON_LIMIT){//正常运载范围
System.out.println(Thread.currentThread().getName()+":向下运载了第:"+list.size()+"位乘客。抵达一楼大厅");
this.notifyAll();
try {
this.wait();//此时电梯到达楼下,下送线程进入等待池,上送线程可以拿到电梯使用权
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();//中断线程
}
System.out.println("---------------[继续DOWN]后续代码继续执行-------------");
}
if(exitFlag){
//终止当前线程,唤醒其他线程
this.notifyAll();
}
}
}

 UpThread 电梯上送工作线程 

 /**
* 上送工作线程
* @function
* @author 小风微凉
* @time 2018-4-26 下午1:48:44
*/
class UpThread implements Runnable{
private Elevator elev;
List<Personnel> list;
public UpThread(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.upCarry(list.subList(0, i),true);
}else{
elev.upCarry(list.subList(0, i), false);
}
}
System.out.println("******[UP线程-END]******************");
}
}

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

 package com.jason.models;

 import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; public class ThreadTest extends Thread{
/**
* @param args
*/
public static void main(String[] args) {
//假设楼上:20人在等待电梯
List<Personnel> topList=new ArrayList<Personnel>();
for(int i=1;i<=20;i++){
topList.add(new Personnel("TOP"+i+"号"));
}
//假设楼下:30人在等待电梯
List<Personnel> bottomList=new ArrayList<Personnel>();
for(int i=1;i<=30;i++){
bottomList.add(new Personnel("BOTTOM"+i+"号"));
}
//创建电梯对象
Elevator elev=new Elevator("1号电梯");
//2种工作线程,随即运载工作人员
new Thread(new UpThread(elev,topList),"UP").start();
new Thread(new DownThread(elev,bottomList),"DOWN").start();
}
}

运行结果:

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)当其中一个线程结束后,主动唤醒另外一个线程继续执行。

好像逻辑蛮简单的,我酝酿下,再出下一个版本吧~

多线程学习-基础( 十一)synchronized关键字修饰方法的简单案例的更多相关文章

  1. 【synchronized锁】通过synchronized锁 反编译查看字节码指令分析synchronized关键字修饰方法与代码块的区别

    前提: 首先要铺垫几个前置的知识: Java中的锁如sychronize锁是对象锁,Java对象头中具有标识位,当对象锁升级为重量级锁时,重量级锁的标识位会指向监视器monitor, 而每个Java对 ...

  2. 多线程学习-基础( 九)线程同步Synchronized关键字

    一.线程同步1.synchronized关键字的作用域有二种:(1)某个对象实例内:synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果 ...

  3. JAVA多线程学习- 三:volatile关键字

    Java的volatile关键字在JDK源码中经常出现,但是对它的认识只是停留在共享变量上,今天来谈谈volatile关键字. volatile,从字面上说是易变的.不稳定的,事实上,也确实如此,这个 ...

  4. Java多线程(三)—— synchronized关键字详解

    一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...

  5. Java 多线程(六) synchronized关键字详解

    多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchroniz ...

  6. 牛客网Java刷题知识点之同步方法和同步代码块的区别(用synchronized关键字修饰)

    不多说,直接上干货! 扩展博客 牛客网Java刷题知识点之多线程同步的实现方法有哪些 为何要使用同步?      java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查 ...

  7. synchronized关键字修饰非静态方法与静态方法的区别

    这里我们先创建ObjLock类,并实现Runnable接口.并创建一个Demo类,具有被synchronized关键字修饰的非静态方法与静态方法. 非静态方法 public class ObjLock ...

  8. 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题

    再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...

  9. [多线程] 线程中的synchronized关键字锁

    为什么要用锁? 在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实 ...

随机推荐

  1. HihoCoder1407 后缀数组二·重复旋律2

    重复旋律2 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为长度为 N 的数构成的数列.小Hi在练习过很多 ...

  2. linux大于2T的磁盘格式化

    fdisk默认只能格式小于2T的磁盘,我们经常会碰到大于2T的磁盘,我们不能fdisk 格式化. 我们得用parted 来的格式化 parted 命令可能没有,yum install -y parte ...

  3. [独孤九剑]Oracle知识点梳理(零)目录

    本系列只涉及到Oracle的具体用法,没有上升到理论层面,都是日常工作中总结积累出的零碎知识点,基本上都是一些使用例子,哪天用到了,可以直接复制出来改改. [独孤九剑]Oracle知识点梳理(一)表空 ...

  4. codevs 2503 失恋28天-缝补礼物

    题目描述 Description 话说上回他给女孩送了n件礼物,由于是廉价的所以全部都坏掉了,女孩很在意这些礼物,所以决定自己缝补,但是人生苦短啊,女孩时间有限,她总共有m分钟能去缝补礼物.由于损坏程 ...

  5. Vue forms

    Vue forms Vue 的表单. 表单中的数据和是双向绑定的. 你可以使用 v-model 对控件元素进行数据双向绑定. 比较有用的修饰符 .lazy .number .trim

  6. Ubuntu 16.04 LTS制作本地源

    平时apt-get install安装软件时,下载的deb文件都会存放在/var/cache/apt/archives/下,没有网络时就需要将这些deb制作成本地源.另外,如果在本机架一个简单的网络服 ...

  7. get方法传递中文数据的时候如何进行转码

    首先,如果是在js端的代码,用window.href进行请求时,需要进行转码 前台jsp中: var param = document.getElementById('param').value;pa ...

  8. [置顶] 自己写一个简单通用的Makefile

    转自:http://blog.csdn.net/u011913612/article/details/52102241 一.makefile的作用 Makefile是用于自动编译和链接的,一个工程有很 ...

  9. 腾讯Web前端开发框架JX(Javascript eXtension tools)

    转自:Web前端开发-Web前端工程师 » 腾讯Web前端开发框架JX(Javascript eXtension tools) JX – Javascript eXtension tools 一个类似 ...

  10. 2010.1.1 CLR 无法从 COM 上下文

    今天做一个程序,sql操作,但是记录数太多,而且sql语句有复杂,就报了这样的错误: CLR 无法从 COM 上下文 0x645e18 转换为 COM 上下文 0x645f88,这种状态已持续 60 ...