public int saveUserToMap(User user) {
ReentrantLock lock;
if(this.userLocks.containsKey(user.getId())) {
lock = this.userLocks.get(user.getId());
} else {
lock = new ReentrantLock();
ReentrantLock check = this.userLocks.putIfAbsent(user.getId(), lock);
if(check != null)
lock = check;
}
if(lock.isLocked())
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.lock();
this.users.put(user.getId(), user);
this.usersByName.put(user.getUsername(), user);
this.usersByEmail.put(user.getEmail(), user);
lock.unlock();
lock.notify();
return user.getId();
}
嘿,我只是想让java开发人员检查我的代码是否是线程安全的,没有死锁,因为我想在我的项目中使用它。 Users,UsersByName和UsersByEmail是ConcurrentHashMap,包含String,Integer作为键,User对象作为Value。 UserLocks是带有Integer的ConcurrentHashMap(显然是用户id作为键)和ReentrantLock作为值。我想同步三个HashMaps。如果有人有更好的解决方案来制作带有三个键的Concurrent地图,那么在此处发布它会很不错。表现也很重要。
这是线程安全的。
如果userId已经在地图中,则代码将获取锁并使用它进行同步。如果没有,ConcurrentHashMap
提供同步,以避免竞争条件为同一个id使用不同的锁。
然后,有一个无用的代码片段,你可以摆脱:
if(lock.isLocked())
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
这不是必需的,因为使用lock.lock()
进行同步。不需要尝试使用wait()
和notify()
再次与锁定对象进行同步。(实际上,它没有按预期工作,多个线程可以在同一个锁定对象上调用lock.isLocked()
并获取错误,直到任何线程调用lock.lock()
,但锁定和解锁之间的所有内容一次只能由一个线程执行。
此外,通常的良好做法是将lock.unlock()
称为finally块。
我会用synchronized
这么简单的方式做到这一点。
class UserMaps {
private Map<Integer, User> users = new ConcurrentHashMap<>();
private Map<String, User> usersByName = new ConcurrentHashMap<>();
private Map<String, User> usersByEmail = new ConcurrentHashMap<>();
public synchronized int put(User user) {
users.put(user.getId(), user);
usersByName.put(user.getUsername(), user);
usersByEmail.put(user.getEmail(), user);
return user.getId();
}
}
只要所有的getter都是synchronized
,这将确保所有地图都一致地更新。
但是,如果你想要更好的表现,并希望避免使用所有的方法synchronized
然后使用ReadWriteLock
。
class UserMaps {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private Map<Integer, User> users = new ConcurrentHashMap<>();
private Map<String, User> usersByName = new ConcurrentHashMap<>();
private Map<String, User> usersByEmail = new ConcurrentHashMap<>();
public int saveUserToMap(User user) {
lock.writeLock().lock();
try {
users.put(user.getId(), user);
usersByName.put(user.getUsername(), user);
usersByEmail.put(user.getEmail(), user);
return user.getId();
} finally {
lock.writeLock().unlock();
}
}
public User getById(int id) {
lock.readLock().lock();
try {
return users.get(id);
} finally {
lock.readLock().unlock();
}
}
}