Lock+HasMap 或 ConcurrentHashMap 在我的例子中?
Lock+HasMap or ConcurrentHashMap in my case?
我有一个Map<String, Queue<?>>
,每次我必须放一对(键,值)时,我需要获取与该键关联的非线程安全队列并向其添加一个值(如果键存在)。因为我需要更新现有值(队列),所以我认为最好的方法是使用 ReentrantLock(Java < 1.5 中的同步块或同步(对象))而不是 ConcurrentHashMap。
这是正确的还是我可以使用 ConcurrentHashMap 而不是 HashMap + Lock?我认为 ConcurrentHashMap 在 get 操作方面效率更高,但我不知道这里是否是正确的解决方案。
private static ReentrantLock lock_Vqueue = new ReentrantLock();
private static HashMap<String,Queue<DocumentObjectHolder>> cacheData = new HashMap<String,Queue<DocumentObjectHolder>>();
/**
* insert element in the tail
* sort the elements by priority
* @param obj a DocumentObjectHolder Object
*/
public static void add(String key, DocumentObjectHolder obj){
ReentrantLock lock = lock_Vqueue; //performance side effect
try{
Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
lock.lock();
if (!cacheData.containsKey(key)){
priorityProcessingVirtualQueue = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
cacheData.put(key, priorityProcessingVirtualQueue);
}
priorityProcessingVirtualQueue = cacheData.get(key);
priorityProcessingVirtualQueue.add(obj);
cacheData.put(key, priorityProcessingVirtualQueue);
}finally {
lock.unlock();
}
}
/**
*
* @return DocumentObjectHolder instance from head of list (FIFO)
*/
public DocumentObjectHolder get(String key){
ReentrantLock lock = lock_Vqueue; //performance side effect
Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
try {
lock.lock();
if (cacheData.containsKey(key)){
priorityProcessingVirtualQueue = cacheData.get(key);
return priorityProcessingVirtualQueue.poll();
}
return null;
}finally{
lock.unlock();
}
}
}
这段代码是正确的还是可以提高性能?
所以你有两个单独的原子指令需要同步。
- 正在将新队列放入地图
- 正在将对象放入队列
这是我的建议。
继续使用ConcurrentHashMap
。您仍然需要 put
进入地图,您也可以使用 CHM 安全地完成它。
使用一个BlockingQueue
。在这种情况下,您可以使用 PriorityBlockingQueue
。
如果您不能执行 (2),则 synchronize
从地图排队。
所以 1 和 3 看起来像:
public static void add(String key, DocumentObjectHolder obj){
Queue<DocumentObjectHolder> priorityProcessingVirtualQueue= cacheData.get(key);
if(priorityProcessingVirtualQueue== null){
Queue<DocumentObjectHolder> temp = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
queue = cacheData.putIfAbsent(key, temp);
if(priorityProcessingVirtualQueue== null){
priorityProcessingVirtualQueue= temp;
}
}
synchronized(priorityProcessingVirtualQueue){
priorityProcessingVirtualQueue.add(obj);
}
}
1 和 2 的唯一区别是缺少 synchronized
。
我们之所以知道这是线程安全的,是因为即使有 2 个或更多线程进入 if(queue == null)
,也只有一个会在 putIfAbsent
中成功。失败的线程将分配 queue
等于成功放入的队列。如果线程获胜(队列 == null 为真),那么我们将分配队列为 we 已创建(我们是获胜线程)。
我有一个Map<String, Queue<?>>
,每次我必须放一对(键,值)时,我需要获取与该键关联的非线程安全队列并向其添加一个值(如果键存在)。因为我需要更新现有值(队列),所以我认为最好的方法是使用 ReentrantLock(Java < 1.5 中的同步块或同步(对象))而不是 ConcurrentHashMap。
这是正确的还是我可以使用 ConcurrentHashMap 而不是 HashMap + Lock?我认为 ConcurrentHashMap 在 get 操作方面效率更高,但我不知道这里是否是正确的解决方案。
private static ReentrantLock lock_Vqueue = new ReentrantLock();
private static HashMap<String,Queue<DocumentObjectHolder>> cacheData = new HashMap<String,Queue<DocumentObjectHolder>>();
/**
* insert element in the tail
* sort the elements by priority
* @param obj a DocumentObjectHolder Object
*/
public static void add(String key, DocumentObjectHolder obj){
ReentrantLock lock = lock_Vqueue; //performance side effect
try{
Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
lock.lock();
if (!cacheData.containsKey(key)){
priorityProcessingVirtualQueue = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
cacheData.put(key, priorityProcessingVirtualQueue);
}
priorityProcessingVirtualQueue = cacheData.get(key);
priorityProcessingVirtualQueue.add(obj);
cacheData.put(key, priorityProcessingVirtualQueue);
}finally {
lock.unlock();
}
}
/**
*
* @return DocumentObjectHolder instance from head of list (FIFO)
*/
public DocumentObjectHolder get(String key){
ReentrantLock lock = lock_Vqueue; //performance side effect
Queue<DocumentObjectHolder>priorityProcessingVirtualQueue;
try {
lock.lock();
if (cacheData.containsKey(key)){
priorityProcessingVirtualQueue = cacheData.get(key);
return priorityProcessingVirtualQueue.poll();
}
return null;
}finally{
lock.unlock();
}
}
}
这段代码是正确的还是可以提高性能?
所以你有两个单独的原子指令需要同步。
- 正在将新队列放入地图
- 正在将对象放入队列
这是我的建议。
继续使用
ConcurrentHashMap
。您仍然需要put
进入地图,您也可以使用 CHM 安全地完成它。使用一个
BlockingQueue
。在这种情况下,您可以使用PriorityBlockingQueue
。如果您不能执行 (2),则
synchronize
从地图排队。
所以 1 和 3 看起来像:
public static void add(String key, DocumentObjectHolder obj){
Queue<DocumentObjectHolder> priorityProcessingVirtualQueue= cacheData.get(key);
if(priorityProcessingVirtualQueue== null){
Queue<DocumentObjectHolder> temp = new PriorityQueue<DocumentObjectHolder>(1, new PriorityComparator());
queue = cacheData.putIfAbsent(key, temp);
if(priorityProcessingVirtualQueue== null){
priorityProcessingVirtualQueue= temp;
}
}
synchronized(priorityProcessingVirtualQueue){
priorityProcessingVirtualQueue.add(obj);
}
}
1 和 2 的唯一区别是缺少 synchronized
。
我们之所以知道这是线程安全的,是因为即使有 2 个或更多线程进入 if(queue == null)
,也只有一个会在 putIfAbsent
中成功。失败的线程将分配 queue
等于成功放入的队列。如果线程获胜(队列 == null 为真),那么我们将分配队列为 we 已创建(我们是获胜线程)。