同步和合并消息传递/数据流

时间:2011-07-07 11:21:09

标签: java concurrency merge messaging sensor

这是非常常见的传感器数据处理问题。

为了同步和合并来自不同来源的传感器数据,我想用Java实现它,而不需要太复杂的第三个库或框架。

说,我定义了一个对象(O),它由例如4个属性(A1,... A4)组成。 4个属性来自不同的数据通道,例如套接字通道。

4个属性通常以1.0~2.0 Hz的速率到达,并且它们的到达彼此独立。 一旦有4个属性(A1,... A4)同时(在一个小时间窗口内,例如100ms),那么我从这4个属性中构造一个新对象(O)。 / p>

描述性场景如下。 A1~A4的到达时间点标有*。

对象O1~U3分别在t1,t2和t3的时间点构成。 一些属性在t2和t3之间到达,但是对于构造Object不完整,因此它们 将被删除并被忽略。

  A1     *          *         *         *
  A2      *           *         *        *
  A3     *            *                  * 
  A4      *            *       *         * 
  --------|------------|-----------------|----------> time
          t1           t2                t3
          O1           O2                O3  

一些要求:

  1. 确定时间点 a.s.a.p。,以便从最后传入的4个属性构建对象。
  2. FIFO,O1必须在O2之前构建,依此类推。
  3. 少用Java锁定
  4. 如果数据不完整则最终丢弃数据以构建对象。
  5. 关于实施的一些快速想法是:

    • 将任何传入属性存储在时间离散桶的FIFO队列中(每个桶包含4个不同的属性)。
    • 如果任何存储桶已经填充了4个不同的属性,
    • 同时运行一个无限的线程来检查FIFO队列(从队列的头部开始)。如果是,则构造一个对象并从队列中删除该存储桶。如果在特定时间窗口内未完成填充,则会将其删除。

    欢迎任何建议和更正!

4 个答案:

答案 0 :(得分:0)

这不太可能解决您的问题,但它可能会指向您正确的方向。

我会先使用Google Guava的MapMaker进行首次尝试:

ConcurrentMap<Key, Bucket> graphs = new MapMaker()
                                   .expireAfterAccess(100, TimeUnit.MILLISECOND)
                                   .makeComputingMap(new Function<Key, Bucket>() {
                                                     public Bucket apply(Key key) {
                                                         return new Bucket(key);
                                                     }
                                    });

这将创建一个地图,如果它们在100毫秒内没有被访问,则其条目将消失,并在被要求时创建一个新的存储桶。

我无法解决的问题正是关键所在:S你真正想要的是队列形式的同类功能。

答案 1 :(得分:0)

这是另一个疯狂的想法:

使用一个LinkedBlockingQueue来从所有传感器A1-A4

写入值

将此队列分配给AtomicReference变量

创建一个计时器任务,该任务将以指定的时间间隔(100毫秒)将该队列切换为新队列

从旧队列中获取所有数据,看看你是否拥有所有数据A1-A4

如果是,则创建对象,否则删除所有内容

答案 2 :(得分:0)

这是另一种方法 - 它只是伪代码,你需要自己编写:)

class SlidingWindow {
    AtomicReference<Object> a1;
    AtomicReference<Object> a2;
    AtomicReference<Object> a3;
    AtomicReference<Object> a4;

    Queue<Long> arrivalTimes = new Queue(4);

    public Bucket setA1(Object data) {
        a1.set(data);
        now = System.currentTimeInMillis()
        long oldestArrivalTime = arrivalTimes.pop();
        arrivalTimes.push(now);
        if (now - oldestArrivalTime < 100) {
            return buildBucket();
        }
        return null;
    }

    public Bucket setA2(Object data) { ...

    ...

    private Bucket buildBucket() {
        Bucket b = new Bucket(a1, a2, a3, a4);
        a1.clear();
        a2.clear();
        a3.clear();
        a4.clear();
        return b;
    }

}

答案 3 :(得分:0)

你可以这样做,get操作阻塞直到数据到达,添加操作没有阻塞。可以稍微优化get操作,以便将候选者保持在并行结构中,这样您在过滤旧项时就不需要迭代所有候选项。但是,迭代4个项目应该足够快。

import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;

public class Filter<V> {

    private static final long MAX_AGE_IN_MS = 100;

    private final int numberOfSources;

    private final LinkedBlockingQueue<Item> values = new LinkedBlockingQueue<Item>();

    public Filter(int numberOfSources) {
        this.numberOfSources = numberOfSources;
    }

    public void add(String source, V data) {
        values.add(new Item(source, data));
    }

    public void get() throws InterruptedException {
        HashMap<String, Item> result = new HashMap<String, Item>();
        while (true) {
            while (result.size() < numberOfSources) {
                Item i = values.take();
                result.put(i.source, i);
                if (result.size() == numberOfSources) {
                    break;
                }
            }
            //We got candidates from each source now, check if some are too old.
            long now = System.currentTimeMillis();
            Iterator<Item> it = result.values().iterator();
            while (it.hasNext()) {
                Item item = it.next();
                if (now - item.creationTime > MAX_AGE_IN_MS) {
                    it.remove();
                }
            }
            if (result.size() == numberOfSources) {
                System.out.println("Got result, create a result object and return the items " + result.values());
                break;
            }
        }
    }

    private class Item {
        final String source;
        final V value;
        final long creationTime;

        public Item(String source, V value) {
            this.source = source;
            this.value = value;
            this.creationTime = System.currentTimeMillis();
        }

        public String toString() {
            return String.valueOf(value);
        }
    }


    public static void main(String[] args) throws Exception {
        final Filter<String> filter = new Filter<String>(4);
        new Thread(new Runnable() {
            public void run() {
                try {
                    filter.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        filter.add("a0", "va0.1");
        filter.add("a0", "va0.2");
        Thread.sleep(2000);
        filter.add("a0", "va0.3");
        Thread.sleep(100);
        filter.add("a1", "va1.1");
        filter.add("a2", "va2.1");
        filter.add("a0", "va0.4");
        Thread.sleep(100);
        filter.add("a3", "va3.1");
        Thread.sleep(10);
        filter.add("a1", "va1.2");
        filter.add("a2", "va2.2");
        filter.add("a0", "va0.5");

    }


}