多线程学习-基础( 十一)synchronized关键字修饰方法的简单案例
一、本案例设计到的知识点
(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关键字修饰方法的简单案例的更多相关文章
- 【synchronized锁】通过synchronized锁 反编译查看字节码指令分析synchronized关键字修饰方法与代码块的区别
前提: 首先要铺垫几个前置的知识: Java中的锁如sychronize锁是对象锁,Java对象头中具有标识位,当对象锁升级为重量级锁时,重量级锁的标识位会指向监视器monitor, 而每个Java对 ...
- 多线程学习-基础( 九)线程同步Synchronized关键字
一.线程同步1.synchronized关键字的作用域有二种:(1)某个对象实例内:synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果 ...
- JAVA多线程学习- 三:volatile关键字
Java的volatile关键字在JDK源码中经常出现,但是对它的认识只是停留在共享变量上,今天来谈谈volatile关键字. volatile,从字面上说是易变的.不稳定的,事实上,也确实如此,这个 ...
- Java多线程(三)—— synchronized关键字详解
一.多线程的同步 1.为什么要引入同步机制 在多线程环境中,可能会有两个甚至更多的线程试图同时访问一个有限的资源.必须对这种潜在资源冲突进行预防. 解决方法:在线程使用一个资源时为其加锁即可. 访问资 ...
- Java 多线程(六) synchronized关键字详解
多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题. 同步机制可以使用synchronized关键字实现. 当synchroniz ...
- 牛客网Java刷题知识点之同步方法和同步代码块的区别(用synchronized关键字修饰)
不多说,直接上干货! 扩展博客 牛客网Java刷题知识点之多线程同步的实现方法有哪些 为何要使用同步? java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查 ...
- synchronized关键字修饰非静态方法与静态方法的区别
这里我们先创建ObjLock类,并实现Runnable接口.并创建一个Demo类,具有被synchronized关键字修饰的非静态方法与静态方法. 非静态方法 public class ObjLock ...
- 并发编程学习笔记(3)----synchronized关键字以及单例模式与线程安全问题
再说synchronized关键字之前,我们首先先小小的了解一个概念-内置锁. 什么是内置锁? 在java中,每个java对象都可以用作synchronized关键字的锁,这些锁就被称为内置锁,每个对 ...
- [多线程] 线程中的synchronized关键字锁
为什么要用锁? 在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实 ...
随机推荐
- Java 参数的和
public class CommandParamter { public static void main(String[] args) { // TODO Auto-generated metho ...
- 1113. Integer Set Partition (25)
Given a set of N (> 1) positive integers, you are supposed to partition them into two disjoint se ...
- Http请求状态码
1xx - 信息提示 这些状态代码表示临时的响应.客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应. ·0 - 本地响应成功. · 100 - Continue 初始的请求已 ...
- GMT时间
GMT:格林尼标准时间 北京时间=GMT时间+8小时
- [转]实现微信浏览器内打开App Store链接
微信浏览器是不支持打开App Store 页面的,不知道微信为什么这么做.比如你页面写 <a href=”http://itunes.apple.com/us/app/id399608199″& ...
- UVA548(二叉树遍历)
You are to determine the value of the leaf node in a given binary tree that is the terminal node of ...
- HDU2181(基础dfs)
哈密顿绕行世界问题 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- 由于簇计数比预计的高,格式化操作无法完成——Allocation Unit Size Adjustments for Larger NTFS Volumes.
Allocation Unit Size Adjustments for Larger NTFS Volumes. Problem: When trying to format a new vol ...
- Day1作业---登录接口及多级菜单
#!/usr/bin/env python # -*- coding:utf-8 -*- # Author:Ma Qing data = { "山东" :{ "济南&qu ...
- Django基础(五)
Django admin 自带的验证: from django.contrib.auth.decorators import login_required from django.contrib.au ...