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

  (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. hadoop碰到的 一个问题

    在里面添加/usr/local/hadoop/etc/hadoop/log4j.properties log4j.logger.org.apache.hadoop.util.NativeCodeLoa ...

  2. Brackets Sequence(升级版)

    个人心得:又是途径问题,我怕是又炸了.看了题解他的意思就是找出最短的添加顺序的断点,则只要 根据断点添加就好了,注意递归的奥妙之处吧,暂时还真得是拿他没办法. 题目描述: 定义合法的括号序列如下: 1 ...

  3. Hive的JDBC访问

    实现hive查询源码: String driverName = "org.apache.hive.jdbc.HiveDriver"; try { Class.forName(dri ...

  4. Nexus安装以及2,3比较

    解压缩之后, 进入nexus-3.6.2-01/bin文件夹中,执行: ./nexus start 如果使用root将会得到一个告警:Detected execution as "root& ...

  5. JSP Servlet中的Request和Response的简单研究

    本文参考了几篇文章所得,参考目录如下: 1.http://www.cnblogs.com/guangshan/p/4198418.html 2.http://www.iteye.com/problem ...

  6. 伪差IO分标准

    伪差分电平 所谓伪差分电平,就是信号在接收端是一个差分的接收器,但其中一端固定接参考电压,而另一端接单端信号线.输入信号电压与参考电压之间进行比较,作为判断输入信号高低的标准. 常用的伪差分电平标准有 ...

  7. javascript一些小的注意点

    try...catch 可以测试代码中的错误.try 部分包含需要运行的代码,而 catch 部分包含错误发生时运行的代码. 当try { 里面的代码 出现错误了 }catch(e){ 才执行下面的c ...

  8. typescript相关知识点总结

    本文讲解typescript语法 由于js语法本身的混乱,再加上目前框架的割据,导致typescript用起来没有一致性,本文尽量总结实际开发中可能会用到的知识点 目录 数据类型 类型断言 duck ...

  9. 一个servlet处理多个请求(使用Method的反射机制)

    方法一 可以通过在请求的时候加上参数,然后在servlet中获取请求的参数,再去调用对应的方法.达到一个servlet处理多个请求的目的 test.jsp: <%@ page language= ...

  10. Django之Model操作进阶篇

    常用参数 null 数据库中字段是否可以为空 db_column 数据库中字段的列名 default 数据库中字段的默认值 primary_key 数据库中字段是否为主键 db_index 数据库中字 ...