美文网首页
线程基础(三十一)

线程基础(三十一)

作者: 叩丁狼教育 | 来源:发表于2019-09-16 10:06 被阅读0次

    本文作者:王一飞,叩丁狼高级讲师。原创文章,转载请注明出处。
    接上篇,本篇讲解线程另外一个设计模式:Guarded Suspension Pattern.

    概念

    Guarded是被守护,被保卫,被保护的意思, Suspension 则是暂停的意思. 如果不满足执行条件,先让当前处理的线程暂停.这就是Guarded Suspension模式.

    参与角色

    Guarded Suspension模式参与角色:
    GuardedObejct: 被守护对象
    被守护对象是一个普通类, 该类拥有2个方法:
    方法1:被守护方法, 线程执行该方法前,先检查是否满足某种条件(守护条件),如果满足马上执行, 如果不满足,线程进行等待.
    方法2:改变守护条件的方法. 守护条件时可变的, 可根据具体情况调用该方法改变守护条件.

    不同线程:
    执行守护方法的线程
    执行改变守护方法的线程


    image.png

    模式特征:

    1:存在循环
    2:存在条件检查
    3:存在不满足条件时等待

    演示案例

    需求:满足5个人,可以开团, 不满足,则等待 (仅仅模拟)

    //用户
    public class User  {
        private String name;
        public User(String name){
            this.name = name;
        }
        public void buy() {
            System.out.println("购买成功.....");
        }
    }
    
    //团:  被守护对象
    public class Group {
    
        //守护条件:
        private volatile int count;
        //守护条件: 当 users.size() == count
        private List<User> users = new ArrayList<User>();
        public Group(int count){
            this.count = count;
        }
        //改变守护条件的方法
        public synchronized void addUser(User user){
            users.add(user);
            System.out.println("增加一人");
            //每次改变了条件判断是否满足开团
            open();
        }
    
        //被守护方法  
        public synchronized void open(){
            while (users.size() < this.count){
                try {
                    System.out.println("还缺:" + (count - users.size()) +"人, 等待:" + Thread.currentThread().getName());
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            for (User user : users) {
                user.buy();
            }
            users.clear();
        }
    }
    
    public class App {
    
        public static void main(String[] args) {
            final Group group = new Group(5);  //5人团
    
            for (int i = 0; i < 11; i++) { //开2团
                final int finalI = i;
                new Thread(new Runnable() {
                    public void run() {
                        group.addUser(new User("user_" + finalI));
                    }
                }).start();
            }
        }
    }
    
    增加一人
    还缺:4人, 等待:Thread-0
    增加一人
    还缺:3人, 等待:Thread-7
    增加一人
    还缺:2人, 等待:Thread-10
    增加一人
    还缺:1人, 等待:Thread-8
    增加一人
    购买成功.....
    购买成功.....
    购买成功.....
    购买成功.....
    购买成功.....
    增加一人
    还缺:4人, 等待:Thread-1
    增加一人
    还缺:3人, 等待:Thread-2
    增加一人
    还缺:2人, 等待:Thread-3
    增加一人
    还缺:1人, 等待:Thread-4
    增加一人
    购买成功.....
    购买成功.....
    购买成功.....
    购买成功.....
    购买成功.....
    增加一人
    还缺:4人, 等待:Thread-6
    

    看上述结果, 在users.size 未等于5人之前, 未满足守护条件, 当前线程挂起等待, 当团人数到达5人时,满足守护条件, 执行后续的方法.

    几个注意点

    1:被守护方法执行前需要循环判断守护条件

    while (守护条件){
        try {
             wait();  //线程等待
        } catch (InterruptedException e) {
             e.printStackTrace();
        }
    }
    //满足条件后处理逻辑
    

    被守护对象中被守护方法中,一般存在循环条件判断,原因很简单, 当线程被唤醒后,还是要进行守护条件判断, 如果此时不满足,继续等待, 满足后执行后续逻辑.

    2:被守护方法使用:synchronized
    被守护的方法加上synchronized, 同一时刻,有且仅有一个线程处理.Guarded Suspension模式跟 single threaded模式有点类型, 区别在于执行被守护方法前进行守护条件判断, 所以认为, Guarded Suspension模式就是加了附加条件的single threaded模式

    3:线程wait跟 notify/notifyAll
    案例中仅仅存在wait 方法调用, 没有notify/notifyAll调用, 这是因为案例中仅仅演示Guarded Suspension模式的特点, 真实场景运用时, 一定要根据实际进行wait跟notify/notifyAll, 否则存在线程持续等待的问题.

    相关文章

      网友评论

          本文标题:线程基础(三十一)

          本文链接:https://www.haomeiwen.com/subject/denhyctx.html