2013-01-02 72 views
3

我正在學習使用Java的多線程編程。這是我得到的一個混亂。Java多線程編程 - 原子操作

class Cache<K, V> { 
private ConcurrentMap<K, V> cache; 
private ConcurrentLinkedQueue<K> lru; 

public Cache() { 
    // initiate cache and lru 
} 

public put (K key, V value) { 
    // some pre-processing 
    synchronized (this) { 
     cache.put(key, value); 
     lru.add(key); 
    } 
    // some post-processing 
} 

} 

這裏是一些非常簡單的緩存與最近最少使用的記錄(lru)。顯然我需要使這兩個操作成爲原子。否則,很可能緩存和lru的狀態會有所不同。

現在假設我想要有一個計時器任務來清理緩存,比方說它會清理緩存的一半。我的問題是我的代碼上面確保這兩個操作(把緩存和添加lru)原子到乾淨的任務?我可以做類似如下:

class CleanTask { 
    Cache cache; // the reference of Cache 
    public void run() { 
     // some pre-processing 
     for (int i = 0; i < n; i++) { // Just suppose I need remove n element 
      synchronized (XXX) { 
       cache.getCache().remove(cache.getLru().poll()); 
      } 
     } 
    } 
} 

我應該在XXX中放什麼?

非常感謝!

+0

您的LRU不應該是該班的公共合同的一部分。你的乾淨的方法應該可能由緩存本身來實現,而不是由外部任務來實現。 – Perception

+1

除非您正在將此作爲學習練習,否則您可能需要查看Google Guava http://code.google.com/p/guava-libraries/wiki/CachesExplained中的緩存包 - 即使它是學習練習,可能值得讓番石榴人們在任何情況下都實施這些事情。 – msandiford

+0

@Perception「LRU不應該成爲班級公共合同的一部分」是什麼意思?我的想法是,當緩存達到其容量時,它將啓動一個線程來執行清理工作,但同時用戶仍應能夠將其放入緩存中。 – shou3301

回答

2

我的問題是我的代碼上面確保這兩個操作(把緩存和添加lru)看起來是乾淨的任務原子?

是(假設清潔作業是在不同的線程)

,我應該把在XXX?

例如相同的緩存對象:synchronized (cache) {一個同步應該發生在同一個鎖(對象)

,您還可以在java中探索其他原子類,如果他們可能是你的情況非常有用:atomic package

+0

''ReentrantReadWriteLock''也值得從'java.util.concurrent.locks'中考慮http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/package-summary.html – msandiford

0

在你的情況,你會在XXX上緩存同步,但是,我建議你看看同步getLru方法作爲替代。