寻找与Java Concurrency API进行事件同步的干净解决方案

时间:2011-07-12 10:09:04

标签: java concurrency

我使用具有Event系统的外部框架,为简单起见,我们说它就像:

public interface EventListener {
    public void eventA(int a);
    public void eventB(int a, long b);
}

因此,事件系统的属性是在事件A之后,可能会或可能不会有针对该事件的事件B。但如果有一个事件B,它需要在3000毫秒内。

我不确定这个问题有什么干净的解决方案,我查看了java.util.concurrency包,但我找不到任何能为这个问题提供干净解决方案的方法。我以为我可能会使用Future<?>,但我无法想出一个很好的解决方案。

我会用伪代码写下我想要做的事情:

public void eventA(int a) {
    // fired Event A

    if (within the next 3 seconds there was an eventB for _exactly_ this a)
        doSomething(a, b)
    else
        doSomething(a)
}

public void eventB(int a, long b) {

}

到目前为止,我使用了一个ConcurrentHashmap<Int, Long>来存储来自eventB的所有ab组合,并检查在过去的3000毫秒内我是否在eventA中得到了这样的ab组合,但我真的不高兴用那个解决方案。我觉得Java 1.5高级并发API需要更清晰的方法。

对于解决该问题的任何提示,我会感到高兴。

2 个答案:

答案 0 :(得分:1)

我不完全确定你是否需要它像这样工作,但它背后的逻辑是当触发eventB时,它将数据添加到ConcurrentHashMap,并安排自己在3秒后删除。当触发eventA时,它会从地图中删除数据(从而清除该键的事件),如果有事件,则调用doSomething(int,long),否则调用doSomething(int)。

import java.util.concurrent.*;

public class EventListenerImpl implements EventListener {

    // You can change how many threads there are, or use a scheduler that's
    // already in the application.
    private final static ScheduledExecutorService scheduler = Executors
            .newScheduledThreadPool(1);

    private ConcurrentHashMap<Integer, Data> data = new ConcurrentHashMap<Integer, Data>();

    @Override
    public void eventA(int a) {

        Data b = data.remove(a);
        if (b != null) {
            doSomething(a, b.getB());
        } else {
            doSomething(a);
        }

    }

    @Override
    public void eventB(final int a, final long b) {

        final Data thisData = new Data(a);

        // Needs to be synchronized because it may be removed by a scheduled event
        synchronized (data) {
            Data d = data.put(a, thisData);
            if (d != null) {
                d.getFuture().cancel(true);
            }
        }

        thisData.setFuture(scheduler.schedule(new Runnable() {

            @Override
            public void run() {
                data.remove(a, thisData);
            }

        }, 3, TimeUnit.SECONDS));

    }

    private class Data {
        private long b;
        private ScheduledFuture<?> future;

        public Data(long b) {
            this.b = b;

        }

        public long getB() {
            return b;
        }

        public void setFuture(ScheduledFuture<?> future) {
            this.future = future;
        }

        public ScheduledFuture<?> getFuture() {
            return future;
        }
    }
}

让我知道这是不是你需要的,因为我有点困惑,最后猜测你想要做什么。例如,如果a不是某种键,那么这可以大大简化......如果eventA在调用doSomething之前等待三秒钟,而不是跟踪最后三秒钟,也可以简化它次。

答案 1 :(得分:0)

使用包含每个收到的事件A的地图,包含收到Foo的时间和潜在A的对象(我们称之为B)最初null

当您收到事件A时,使用当前时间和空Foo创建一个B实例,将其存储在地图中,然后启动一个休眠的线程3秒,然后检查与Foo关联的A是否包含B,从地图中删除条目,并相应地采取行动(即使用适当的参数调用doSomething )。

当您收到B时,检查地图中是否有Foo以及是否收到的时间少于3秒(尽管不应该发生),并存储B中的Foo

当然,您必须在需要时进行同步。