首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >并发频率计数器更新java

并发频率计数器更新java
EN

Stack Overflow用户
提问于 2017-11-11 19:59:09
回答 1查看 725关注 0票数 4

我正在尝试实现一个频率计数器来计数每个元素的出现情况。在这种情况下,两个进程可以同时调用hfc.count(1)和hfc.count(2)。我在总结进程的数量,以确保它的2000000,但我是差不多100000。

代码语言:javascript
复制
class FrequencyCounter {
HashMap<Integer, Integer> frequencyMap = new HashMap<Integer, Integer>();
int max ;

FrequencyCounter(int max) {
    this.max = max ;
    for (int i = 0; i < max; i++) {
        frequencyMap.put(i, 0);
    }
}

void count(int event) {
    synchronized (this) {
        if (frequencyMap.containsKey(event)) {
            frequencyMap.put(event, frequencyMap.get(event) + 1);
        }
    }
}

/**
 * @param event
 * @return the frequency of event since creation.
 */
int frequency(int event) {

    return frequencyMap.get(event);
}

并发freq计数器

代码语言:javascript
复制
class HighFrequencyCounter extends FrequencyCounter {

int[] count;
static int n;

/**
 * @ClassInvariant {frequencyMap != null && max > 0}
 */

HighFrequencyCounter(int max) {
    super(max);

    count = new int[max];
}

void count(int event) {
    if (count[event] != 0) {
        n++;
        super.count(event);
    }
    if (count[event] < 1) {
        count[event] = 1;
        frequencyMap.put(event, frequencyMap.get(event) + 1);
        count[event] = 0;

    }
}

public static void main(String Args[]) throws InterruptedException {

    class HEventer extends Thread {
        HighFrequencyCounter hfc;

        HEventer(HighFrequencyCounter hfc) {
            this.hfc = hfc;
        }

        public void run() {
            Random r = new Random();
            for (int i = 0; i < 20000; i++) {
                hfc.count(r.nextInt(10));
            }
        }
    }

    HighFrequencyCounter hfc = new HighFrequencyCounter(10);
    HEventer hev[] = new HEventer[1000];
    for (int i = 0; i < 1000; i++) {
        hev[i] = new HEventer(hfc);
    }

    long hstartTime = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++) {
        hev[i].start();
    }
    for (int i = 0; i < 1000; i++) {
        hev[i].join();
    }
    long hendTime = System.currentTimeMillis();
    System.out.println(hendTime - hstartTime);

    int sumProcesses = 0;
    for (int i = 0; i < 10; i++) {
        System.out.println(i + " =  " + hfc.frequency(i));
        sumProcesses = sumProcesses + hfc.frequency(i);

    }
    System.out.println(sumProcesses);
    System.out.println(hfc.n);

}

}

我知道使用java的并发散列映射是可能的,但我只是尝试同步简单的hashmap。我的普通frequencyCounter类可以正常工作,但我不确定如何同步计数方法。

对于高频计数器,我同步了count方法,并在while(countevent != 0) wait()中使用了wait,但是这允许并发调用,因为我需要同步count方法。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-11-11 20:28:08

您需要同步对frequencyMap的所有共享访问,而不仅仅是在写入它时。由于写入映射是由this上的锁保护的,所以在读取映射时需要在同一锁上同步。

代码语言:javascript
复制
int frequency(int event) {
    synchronized (this) {
        return frequencyMap.get(event);
    }
}

如果没有同步,一个线程可能看不到另一个线程编写的内容。这就解释了你得到的不一致的值。

顺便说一下,我注意到构造函数将映射中的初始值设置为范围[0..max)中的0。如果映射只在此范围内使用键,则数组将比散列映射更合适和更轻。

正如你在评论中所写的:

我的问题是关于HighFrequencyCounter的计数(事件)函数。如果我想允许两个不同整数事件的线程(比如hfc.count(4)hfc.count(3)并发运行,而不是两个并发调用hfc.count(3) ),我使用count[0..Max]作为数组来保存条件。这就是我在同步过程中遇到的困难

根据这个描述,每个计数器需要一个锁。下面是一个简单的实现,使用一个数组进行计数,另一个用于锁:

代码语言:javascript
复制
class FrequencyCounter {
    private final int[] counts;
    private final Object[] locks;

    FrequencyCounter(int max) {
        counts = new int[max];
        locks = new Object[max];
        IntStream.range(0, max).forEach(i -> locks[i] = new Object());
    }

    void count(int event) {
        synchronized (locks[event]) {
            counts[event]++;
        }
    }

    int frequency(int event) {
        synchronized (locks[event]) {
            return counts[event];
        }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47242220

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档