在我的應用程序中,我需要確保對於表示數據庫中的數據行的實體 我最多隻有一個代表它的java對象。WeakMultiton:確保對於特定數據庫行只有一個對象
確保它們是等於()是不夠的,因爲我可能會遇到一致性問題。所以基本上我需要一個multiton;此外,當不需要時,我不需要將這個對象保存在內存中,所以我將使用弱引用。
我設計了這樣的解決方案:
package com.example;
public class DbEntity {
// a DbEntity holds a strong reference to its key, so as long as someone holds a
// reference to it the key won't be evicted from the WeakHashMap
private String key;
public void setKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
//other stuff that makes this object actually useful.
}
package com.example;
import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import java.util.concurrent.locks.ReentrantLock;
public class WeakMultiton {
private ReentrantLock mapLock = new ReentrantLock();
private WeakHashMap<String, WeakReference<DbEntity>> entityMap = new WeakHashMap<String, WeakReference<DbEntity>>();
private void fill(String key, DbEntity object) throws Exception {
// do slow stuff, typically fetch data from DB and fill the object.
}
public DbEntity get(String key) throws Exception {
DbEntity result = null;
WeakReference<DbEntity> resultRef = entityMap.get(key);
if (resultRef != null){
result = resultRef.get();
}
if (result == null){
mapLock.lock();
try {
resultRef = entityMap.get(key);
if (resultRef != null){
result = resultRef.get();
}
if (result == null){
result = new DbEntity();
synchronized (result) {
// A DbEntity holds a strong reference to its key, so the key won't be evicted from the map
// as long as result is reachable.
entityMap.put(key, new WeakReference<DbEntity>(result));
// I unlock the map, but result is still locked.
// Keeping the map locked while querying the DB would serialize database calls!
// If someone tries to get the same DbEntity the method will wait to return until I get out of this synchronized block.
mapLock.unlock();
fill(key, result);
// I need the key to be exactly this String, not just an equal one!!
result.setKey(key);
}
}
} finally {
// I have to check since I could have already released the lock.
if (mapLock.isHeldByCurrentThread()){
mapLock.unlock();
}
}
}
// I synchronize on result since some other thread could have instantiated it but still being busy initializing it.
// A performance penality, but still better than synchronizing on the whole map.
synchronized (result) {
return result;
}
}
}
WeakMultiton將只在數據庫中包裝(訪問數據庫的單點)和其get(String鍵)被實例化當然是唯一的辦法檢索一個DbEntity。 現在,據我所知,這應該可行,但由於這些東西對我來說很新,所以我擔心我可能會監督關於同步或弱引用的內容! 你能發現任何缺陷或建議改進嗎?
我還沒有使用可重入鎖,所以我不是100%肯定的,但並不是所有的代碼路徑都會導致你的地圖解鎖。我建議在'try'塊內移動'mapLock.lock()',然後將'maoLock.unlock()'放在'finally'塊中。至於其餘部分,我不能和任何權威機構談論它的有效性。 – jpm
對,我最初把解鎖放在一個finally塊中,然後忘了爲什麼我做了它,並把它移到一個catch :) 我看不到移動鎖的嘗試,雖然... – lultimouomo
我相應地更正了代碼 – lultimouomo