blu*_*Sky 7 java concurrency multithreading thread-safety
我有以下课程.我使用ConcurrentHashMap.我有很多线程写入地图和一个Timer,每5分钟将数据保存在地图中.当我在地图中写入条目时,我设法通过使用putIfAbsent()来实现线程安全.但是,当我从中读取然后通过clear()方法删除所有条目时,我希望在我正在读取地图内容然后删除它们的过程中没有其他线程写入映射.显然,我的代码没有与之同步(锁)即使线程安全{},B/C拥有在saveEntries)锁(线程,不一定是写入我的地图中的log()方法相同的线程!除非我使用相同的锁对象锁定log()中的整个代码!
我想知道是否还有其他方法来实现线程安全,而无需通过外部锁执行同步?任何帮助是极大的赞赏.
public class Logging {
private static Logging instance;
private static final String vendor1 = "vendor1";
private static final String vendor2 = "vendor2";
private static long delay = 5 * 60 * 1000;
private ConcurrentMap<String, Event> vendor1Calls = new ConcurrentHashMap<String, Event>();
private ConcurrentMap<String, Event> vendor2Calls = new ConcurrentHashMap<String, Event>();
private Timer timer;
private final Object lock = new Object();
private Logging(){
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
try {
saveEntries();
} catch (Throwable t) {
timer.cancel();
timer.purge();
}
}
}, 0, delay);
}
public static synchronized Logging getInstance(){
if (instance == null){
instance = new Logging();
}
return instance;
}
public void log(){
ConcurrentMap<String, Event> map;
String key = "";
if (vendor1.equalsIgnoreCase(engine)){
map = vendor1Calls;
}else if(vendor2.equalsIgnoreCase(engine)){
map = vendor2Calls;
}else{
return;
}
key = service + "." + method;
// It would be the code if I use a regular HashMap instead of ConcurrentHashMap
/*Event event = map.get(key);
// Map does not contain this service.method, create an Event for the first time.
if(event == null){
event = new Event();
map.put(key, event);
// Map already contains this key, just adjust the numbers.
}else{
// Modify the object fields
}*/
//}
// Make it thread-safe using CHM
Event newEvent = new Event();
Event existingEvent= map.putIfAbsent(key, newEvent);
if(existingEvent!=null && existingEvent!=newEvent){
// Modify the object fields
}
private void saveEntries(){
Map<String, List<Event>> engineCalls = null;
try {
engineCalls = new HashMap<String, List<Event>>();
List<Event> events = null;
// How can I achieve therad safety here w/o applying any lock?
//synchronized(lock){
if(!vendor1Calls.isEmpty()){
events = new ArrayList<Event>();
events.addAll(vendor1Calls.values());
engineCalls.put(vendor1, events);
vendor1Calls.clear();
}
if(!vendor2Calls.isEmpty()){
events = new ArrayList<Event>();
events.addAll(vendor2Calls.values());
engineCalls.put(vendor2, events);
vendor2Calls.clear();
}
//}
// logICalls() saves the events in the DB.
DBHandle.logCalls(engineCalls);
} catch (Throwable t) {
} finally {
if(engineCalls!=null){
engineCalls.clear();
}
}
}
Run Code Online (Sandbox Code Playgroud)
}
\n\n\n但是,当我从中读取内容然后通过clear()\n方法删除所有条目时,我不希望其他线程写入映射,而在读取映射内容然后删除它们的过程中\n I\xe2\x80\x99m 。
\n
我认为你想说的是你并不真正关心严格锁定地图。相反,您只关心 vender1Calls.values() 和vendor1Calls.clear() 之间任何日志条目的丢失,对吗?
\n\n在这种情况下,我可以想象你可以替换
\n\nevents.addAll(vendor1Calls.values());\nvendor1Calls.clear();\nRun Code Online (Sandbox Code Playgroud)\n\n在 saveEntries 中使用这个:
\n\nfor (Iterator<Event> iter = vendor1Calls.values().iterator(); iter.hasNext(); ) {\n Event e = iter.next();\n events.add(e);\n iter.remove();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n这样,您只需删除已添加到事件列表中的事件。当 saveEntries() 仍在执行时,您仍然可以写入vendor1Calls 映射,但迭代器会跳过添加的值。
\n| 归档时间: |
|
| 查看次数: |
9919 次 |
| 最近记录: |