簡體   English   中英

並發頻率計數器更新java

[英]Concurrent frequency counter updates java

我正在嘗試實現一個計數每個元素出現次數的頻率計數器。 在這種情況下,兩個進程可以同時調用hfc.count(1)和hfc.count(2)。 我總結了確保2000000的進程數量,但是我差不多就像~100000。

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);
}

並發頻率計數器

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的並發hashmaps,但我試圖同步只是簡單的hashmaps。 我的普通frequencyCounter類確實按預期工作,但我不確定如何同步count方法。

對於高頻計數器我同步了count方法,並在while內使用wait(count [event]!= 0)wait()但是這允許並發調用,因為我需要同步count方法。

您需要同步所有對frequencyMap共享訪問,而不僅僅是在寫入時。 由於this進行鎖定可以防止寫入地圖, this在從地圖讀取時需要在同一個鎖上進行同步。

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]作為保持條件的數組。 這是我在同步中遇到困難的地方

根據此描述,每個計數器需要一個鎖。 這是一個簡單的實現,使用一個數組作為計數,一個用於鎖:

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];
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM