线程间同步工具

线程间同步工具

当一个任务被分解成多个任务并行执行完成时,各个任务间难免有相互依赖关系,比如,任务A为界面创建并更新的工作,任务B为网络获取数据,当任务A执行时,B可以同时去获取数据,A进行页面刷新时,可能会依赖B获取到的数据进行界面显示,这时,A需要等待B的完成,才能进行后续工作。
基于类似场景的解决方案很多,本文编写的工具类,个人感觉使用上可能稍微便捷一些。当然有得必有失,同仁们取长补短吧。

本文所写工具类命名为ConditionUtil, 基本原理很简单,主要是封装了Object.java的wait/notify机制。ConditionUtil内部会全局保存需要等待的condition在字典中, condition可以用字符串索引,condition被解除等待后,会从字典中移除。使用上的简便之处在于,等待和解除等待的操作都是针对某一个字符串的操作,也就是以一个字串唯一命名一个等待条件,对于解耦有一定的帮助。

举例如下:

在某个时间点对condition进行创建:
1.
ConditionUtil.getInstance().createCondition(“condition_util_test”);
//首先创建一个等待条件,针对某一个condition, 创建操作要先于等待操作,否则不会对该 condition进行等待

2.
A任务:
ConditionUtil.getInstance().wait(“condition_util_test”);
//对condition进行等待,该A任务线程被block, 等待B任务对该condition进行signal解锁
或者使用:ConditionUtil.getInstance().wait(“condition_util_test”, WAIT_TIMEOUT)

3.
B任务:
ConditionUtil.getInstance().signal(“condition_util_test”);
//B任务完成后,调用signal对该condition解锁,A任务线程继续执行

4.
在某个时间点对condition进行移除:
ConditionUtil.getInstance().removeCondition(“condition_util_test”);

总结:

1.signal操作先于wait操作之前被触发
如上所述,对condition要先进行创建,signal和removeCondition操作均表示此次与该condition相关的操作均满足解锁条件,不需要再等待. signal先于wait触发,wait操作不会再block线程,线程直接继续执行.

2.signal操作一直没有被触发
采用timeout机制,timeout后,线程继续执行,如果设置了timeout回调,该回调函数被
调用.

3.ConditionUtil中保存Condition的存储释放

import java.util.HashMap;

public class ConditionUtil {
    private static ConditionUtil self;
    private HashMap<String, ConditionInUse> map;

    private interface ConditionTimeoutCallback {
        void onTimeout();
    }

    private ConditionUtil() {
        map = new HashMap<>();
    }

    public synchronized static ConditionUtil getInstance() {
        if (self == null) {
            self = new ConditionUtil();
        }

        return self;
    }

    private class ConditionInUse {
        private volatile boolean mCondition;
        private ConditionTimeoutCallback timeoutCallback;
        private int waitCount = 0;

        public ConditionInUse() {
            mCondition = false;
        }

        public int getWaitCount() {
            return waitCount;
        }

        private void open() {
            synchronized (this) {
                boolean old = mCondition;
                mCondition = true;
                if (!old) {
                    this.notifyAll();
                }
            }
        }

        private void close() {
            synchronized (this) {
                mCondition = false;
            }
        }

        public void block() {
            waitCount++;
            synchronized (this) {
                while (!mCondition) {
                    try {
                        this.wait();
                    }
                    catch (InterruptedException e) {
                        waitCount--;
                    }
                }
            }
            waitCount--;
        }

        public boolean block(long timeout) {
            waitCount++;
            if (timeout > 0) {
                synchronized (this) {
                    long now = System.currentTimeMillis();
                    long end = now + timeout;
                    while (!mCondition && now < end) {
                        try {
                            this.wait(end-now);
                        }
                        catch (InterruptedException e) {
                            waitCount--;
                        }
                        now = System.currentTimeMillis();
                    }
                    if (!mCondition && end < now && timeoutCallback != null) {
                        timeoutCallback.onTimeout();
                    }
                    waitCount--;
                    return mCondition;
                }
            } else {
                this.block();
                waitCount--;
                return true;
            }
        }

        public void setTimeoutCallback(ConditionTimeoutCallback callback) {
            timeoutCallback = callback;
        }
    }

    public void createCondition(String str) {
        if (str == null) {
            return;
        }

        synchronized (map) {
            ConditionInUse condition = map.get(str);
            if (condition == null) {
                condition = new ConditionInUse();
                map.put(str, condition);
            }
        }
    }

    public void removeCondition(String str) {
        if (str == null) {
            return;
        }

        synchronized (map) {
            ConditionInUse condition = map.get(str);
            if (condition != null) {
                condition.close();
                condition.open();
                map.remove(str);
            }
        }
    }

    public void wait(final String str, long time) {
        if (str == null) {
            return;
        }

        final ConditionInUse condition = map.get(str);
        if (condition != null) {
            condition.setTimeoutCallback(new ConditionTimeoutCallback() {
                @Override
                public void onTimeout() {
                    //do something here to handle timeout
                    if (condition.getWaitCount() == 0) {
                        //map.remove(str); 取消移除操作, 使用removeCondition进行手动移除
                    }
                }
            });
            condition.block(time);
        }
    }

    public void wait(final String str) {
        if (str == null) {
            return;
        }

        final ConditionInUse condition = map.get(str);
        if (condition != null) {
            condition.block();
        }
    }

    public void signal(final String str) {
        removeCondition(str);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值