Java 多线程(Thread) 同步(synchronized) 以及 wait, notify 相关 [实例介绍]
场景描述
有一家很大的商场,在某市有几个商品配送中心,并有几家分店,这家商场经营很多的商品,平时运营情况是这样的:
根据各分店的商品销售情况,给分店配送相应需求量的商品;并上架到分店指让的位置,供客户选购。
客户选择自己需要的商品,然后到收银台交钱打包;
然后到一天的某个时候分店管理员(经理等),开始统计当前的销售情况,并计划向商品配送中心订购各商品的配送量;
场景模拟
1. 商场类;
public class StoreMart {
    //商场这一天剩余的商品量
    private static Map<String, Integer> goodsMap = new HashMap<String, Integer>();
    private static Map<String, Integer> priceMap = new HashMap<String, Integer>();
    static {
        goodsMap.put("ap", 1000);
        goodsMap.put("bp", 500);
        goodsMap.put("cp", 2000);
        priceMap.put("ap", 20);
        priceMap.put("bp", 50);
        priceMap.put("cp", 30);
        //...
    }
    //选择商品
    //pn 商品名称
    //num 选购数量
    public synchronized void selGoods(String name,String pn, int num) {
        int total = getNum(pn);
        int remain = total - num;
        goodsMap.put(pn, remain);
        //保存用户购物车信息
    }
    //新增商品数据
    public synchronized void putGoods(String pn, int num) {
        int total = getNum(pn);
        total = total + num;
        goodsMap.put(pn, total);
    }
    public static int getNum(String pn) {
        int num = 0;
        if (goodsMap.containsKey(pn)) {
            num = goodsMap.get(pn);
        }
        return num;
    }
    //结算
    public void settleGoods(Map<String, Integer> goods) {
        //....
    }
}
用户购物类:
public class UserShop implements Runnable {
    private static StoreMart sm = new StoreMart();
    private final String name;
    private final Map<String, Integer> sgoods = new HashMap<String, Integer>();
    public UserShop(String name) {
        this.name = name;
    }
    public void add(String pn, int num) {
        sgoods.put(pn, num);
    }
    public void run() {
        for(Map.Entry<String, Integer> entry:sgoods.entrySet()){
            sm.selGoods(entry.getKey(), entry.getValue());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        sm.settleGoods(sgoods);
        System.out.println(this.name + " 购物完毕! ");
    }
    public static void main(String[] args) {
        UserShop u1 = new UserShop("NameA");
        u1.add("ap",1);
        u1.add("bp",2);
        Thread t1 = new Thread(u1);
        UserShop u2 = new UserShop("NameB");
        u1.add("ap",4);
        u1.add("bp",5);
        Thread t2 = new Thread(u2);
        t1.start();
        t2.start();
    }
}
以上摸拟的是商品数量都充足的情况;
摸拟了两个客户 各购买了 不同数量的商品 ap, bp;
但是如果万一用户多了起来,如果有几个客户一下子要选购同一个商品很多的量;就会出问题了;
使用 wait(), notify()
修改 下 StoreMart 类:
//选择商品
//pn 商品名称
//num 选购数量
public synchronized void selGoods(String name,String pn, int num) {
int total = getNum(pn);
while (total < num) {
System.out.println(pn + "商品量不够");
this.wait();
}
int remain = total - num;
goodsMap.put(pn, total); //保存用户购物车信息
} //新增商品数据
public synchronized void putGoods(String pn, int num) {
int total = getNum(pn);
total = total + num;
goodsMap.put(pn, total);
this.notify();
}
在UserShop 的 run 方法里,添加商品不足补货的语句:
public void run() {
    for(Map.Entry<String, Integer> entry:sgoods.entrySet()){
        sm.selGoods(entry.getKey(), entry.getValue());
        try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        //发现商品不够了
        sm.putGoods("ap", 100);
        sm.putGoods("bp", 200);
        System.out.println(this.name + " 购物完毕! ");
}
这样 当商场里的 某商品量不足时,NameA 或 NameB 就得处于等待状态,就是要wait() 到等待集合,等待被 notify() 换醒;
synchronized, wait, notify说明
1. wait;
1>. 用于 当本 线程不能成立时,放弃当前占用的锁;
2>. wait 必须要在 synchronized 所在的代码块内;
3>. wait 是 Object 的方法;
4>. 一般要处理 while 循环 体内; 用于重新判断条件是否满足;
2. synchronized 一般结束多线程环境下,用于处理 占用 共享资源的问题;
3. notify 用于 唤醒 wait() 的线程;
wait 与 sleep 的区别
wait 针对的是 当前 synchronized 所在块的机锁:
1>. synchronized 如果 标识一个 普通类,那机锁就为当前 所在对象的 锁;
2>. synchronized 如果 标识一个 静态类,那机锁 就为所在类的类锁;
3>. 如果是 synchronized (obj) ,则 锁 为 obj 对象; 一般这个锁可以定义为 0 长度的 byte 数组,比较经济;
sleep 针的是当前 Thread;
sleep 一般是定时执行的;
wait 是需要竞争的,能否执行,得看本次锁是否分配给了它,本且条件是否满足;
interrupt() 都可以中止 sleep 或 wait 的暂停状态;如果线程 A 要中止 线程 B,则调用 线程B实例的 interrupt() 方法,当 线程B处于 wait(),sleep(),join() 时,就会抛出 InterruptedException 异常,在 catch 块执行 return ,即可正常结束线程;
Java 多线程(Thread) 同步(synchronized) 以及 wait, notify 相关 [实例介绍]的更多相关文章
- Java多线程5:Synchronized锁机制
		一.前言 在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的. 二.引入Synchronized ... 
- Java多线程编程(同步、死锁、生产消费者问题)
		Java多线程编程(同步.死锁.生产消费): 关于线程同步以及死锁问题: 线程同步概念:是指若干个线程对象并行进行资源的访问时实现的资源处理保护操作: 线程死锁概念:是指两个线程都在等待对方先完成,造 ... 
- java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析
		java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ... 
- Java多线程6:Synchronized锁代码块(this和任意对象)
		一.Synchronized(this)锁代码块 用关键字synchronized修饰方法在有些情况下是有弊端的,若是执行该方法所需的时间比较长,线程1执行该方法的时候,线程2就必须等待.这种情况下就 ... 
- Java多线程的同步控制记录
		Java多线程的同步控制记录 一.重入锁 重入锁完全可以代替 synchronized 关键字.在JDK 1.5 早期版本,重入锁的性能优于 synchronized.JDK 1.6 开始,对于 sy ... 
- Java多线程之同步集合和并发集合
		Java多线程之同步集合和并发集合 不管是同步集合还是并发集合他们都支持线程安全,他们之间主要的区别体现在性能和可扩展性,还有他们如何实现的线程安全. 同步集合类 Hashtable Vector 同 ... 
- Java多线程的同步机制(synchronized)
		一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个 ... 
- Java多线程简析——Synchronized(同步锁)、Lock以及线程池
		Java多线程 Java中,可运行的程序都是有一个或多个进程组成.进程则是由多个线程组成的.最简单的一个进程,会包括mian线程以及GC线程. 线程的状态 线程状态由以下一张网上图片来说明: 在图中, ... 
- Java多线程之二(Synchronized)
		常用API method 注释 run() run()方法是我们创建线程时必须要实现的方法,但是实际上该方法只是一个普通方法,直接调用并没有开启线程的作用. start() start()方法作用为使 ... 
随机推荐
- VMware在Centos7上配置静态IP的方法
			使用NAT模式 在这里记下192.168.161.2 进入系统,为系统自动分配一个ip 记录下 192.168.161.129 进入网络管理器配置文件目录 cd /etc/sysconfig/netw ... 
- 20181023-3 每周例行报告(添加PSP)
			此作业要求:[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2100] 一.本周PSP表格 类型 任务 开始时间 结束时间 中断时间 净时 ... 
- Linux下C语言编程基础学习记录
			VIM的基本使用 LINUX下C语言编程 用gcc命令编译运行C语言文件 预处理阶段:将*.c文件转化为*.i预处理过的C程序. 编译阶段:将*.i文件编译为汇编代码*.s文件. 汇编阶段:将*.s ... 
- 小学四则运算APP 第一个冲刺阶段 第三天
			团队成员:陈淑筠.杨家安.陈曦 团队选题:小学四则运算APP 第一次冲刺阶段时间:11.17~11.27 本次发布是在与团队成员解决了昨天问题的基础上,再增加了几个界面,增加了一些功能,修改与增加的代 ... 
- java向上转型和向下转型
			转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展. 向上转型:子类引用的对象 ... 
- 在eclipse中编译调试ns3
			1首先把ns3项目导入eclipse 然后把上面的的ns3按照上面的提示即可导入成功. 然后可以运行一下 ./waf configure 2 配置C/C++ Build 右键工程,选择属性 ... 
- jQuery3 slim版本和普通版本区别,如何选择?
			区别概述: slim即简化版,比普通版本缺少Ajax和特效模块模块. 官方发布地址:http://blog.jquery.com/2017/03/20/jquery-3-2-1-now-availab ... 
- HUAS 2018暑假第一周比赛-题解
			小朋友们有问题评论区 :) B. 子串计算 难度系数 : ☆ Main idea : 模拟 暴力 按照题目的要求一步一步来就行了 之所以可行的原因是从左往右扫,如果扫到一个子串,把它删除掉之后,假设当 ... 
- python day4 ---------------文件的基本操作
			1.能调用方法的一定是对象,比如数值.字符串.列表.元组.字典,甚至文件也是对象,Python中一切皆为对象. str1 = 'hello' str2 = 'world' str3 = ' '.joi ... 
- SSH协议详解
			简介 SSH只是一个协议,基于这个协议有不同的实现,这些实现中有开源,也有收费. 原理 普通网络通信一般是明文通信,数据容易被中间人拦截并且解析,而SSH协议则提供了基于内容加密服务. 流程: 第一种 ... 
