我想實現的是分配資源(字符串,保存在一個數組)到多個客戶端,可以試圖獲取一組資源的鎖,並給出一個ID解鎖的資源處理類通過鎖定方法。資源經理ReentrantLocks
我想使用公平的ReentrantReadWriteLock-s,每個資源的一個。
我只看到客戶端的日誌。
有幾個問題,有時線程不會停止請求和獲取資源,有時會發生死鎖,有時會發生releaseLock失敗。 任何提示讚賞。
public class ResHandler {
//ID-s of the granted resource lists
private static long lockNum = 0;
//Resources are identified by strings, each client has a list of demanded resources
//we store these when granted, along with an ID
private static ConcurrentHashMap<Long, Set<String>> usedResources
= new ConcurrentHashMap<Long, Set<String>>();
//We store a lock for each resource
private static ConcurrentHashMap<String, ReentrantReadWriteLock> resources
= new ConcurrentHashMap<String, ReentrantReadWriteLock>();
//Filling our resources map with the resources and their locks
static {
for (int i = 0; i < SharedValues.RESOURCE_LIST.length; ++i) {
String res = SharedValues.RESOURCE_LIST[i];
//Fair reentrant lock
ReentrantReadWriteLock lc = new ReentrantReadWriteLock(true);
resources.put(res, lc);
}
}
//We get a set of the required resources and the type of lock we have to use
public static long getLock(Set<String> mNeededRes, boolean mMethod) {
//!!!
if (mMethod == SharedValues.READ_METHOD) {
//We try to get the required resources
for (String mn : mNeededRes)
resources.get(mn).readLock().lock();
//After grandted, we put them in the usedResources map
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
//Same thing, but with write locks
else {
for (String mn : mNeededRes)
resources.get(mn).writeLock().lock();
++lockNum;
usedResources.put(lockNum, mNeededRes);
return lockNum;
}
}
//Releasing a set of locks by the set's ID
public static void releaseLock(long mLockID) {
if (!usedResources.containsKey(mLockID)) {
System.out.println("returned, no such key as: " + mLockID);
return;
}
Set<String> toBeReleased = usedResources.get(mLockID);
//Unlocking every lock from this set
for (String s : toBeReleased) {
if (resources.get(s).isWriteLockedByCurrentThread())
resources.get(s).writeLock().unlock();
else
resources.get(s).readLock().unlock();
}
//Deleting from the map
usedResources.remove(mLockID);
}
}
還有一兩件事是我百思不得其解:字符串在Java不變。換句話說,鎖定或不鎖定,無論如何你都不能寫入字符串!但無論如何,讓我們假設這些只是作爲例子。在這種情況下,重要的是所有的鎖都是以相同的順序獲取以避免死鎖,請驗證Set <>是否可以保證這一點。然後,您不僅可以存儲鎖ID,還可以存儲擁有這些ID的線程ID。這樣你就可以確保一個線程不釋放任何它不擁有的東西,並且一個線程在釋放之前不會再次鎖定,這可能會再次因爲該命令而死鎖。 – 2013-04-27 16:07:34
字符串不被修改,它們只代表資源,客戶端只是等待它們。 我嘗試了你的建議,而不是集合,我使用一個Vector來存儲resourceName和鎖對,另一個Vector來存儲分配,所以鎖以相同的順序獲取。在釋放我也檢查線程。我也使lockNum變得不穩定。 問題仍然存在。 – user1875619 2013-04-27 18:26:25
我不認爲使用矢量有幫助,因爲那個確實沒有排序。更糟糕的是,我相信一套你有保證,沒有重複,而在一個載體中,你沒有。也就是說,在代碼中是一個使用'lockNum'的競爭條件:你增加它,第二個線程遞增它,然後使用相同的值。 'volatile'在這裏沒有幫助,可能會使函數同步。順便說一句:對整個資源管理使用單個鎖將解決您的問題,但您必須自己實施一些細粒度鎖定功能。 – 2013-04-27 19:15:37