zoukankan      html  css  js  c++  java
  • 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 ,即可正常结束线程;

  • 相关阅读:
    day_01 python基础 基本数据类型 if条件
    计算多边形周长和面积
    我研究出来的属性查询,贴自己的代码,请大家指教
    配置sde
    如何编辑SDE数据库(转载)
    ArcSED连接方式
    不同窗体传递数据
    sde stuff
    ArcSED
    不显示查询问题的解决(太完美了,新建一个图层,表示查询结果)
  • 原文地址:https://www.cnblogs.com/editor/p/4115863.html
Copyright © 2011-2022 走看看