Java 此方法是否可以在线程安全且无死锁的情况下工作
嘿,我只想让java开发人员检查我的代码是否是线程安全的,并且没有死锁,因为我想在我的项目中使用它。 Users、UsersByName和UsersByMail是ConcurrentHashMap,字符串、整数作为键,用户对象作为值。UserLocks是一个ConcurrentHashMap,其中整数(显然是用户id作为键)和ReentrantLock作为值。 我想同步这三个哈希映射。 如果有人有一个更好的解决方案来创建一个带有三个键的并发映射,那么在这里发布它会很好。性能也很重要。它是线程安全的 如果用户ID已经在映射中,代码将获得锁并使用它进行同步。否则,Java 此方法是否可以在线程安全且无死锁的情况下工作,java,concurrency,thread-safety,deadlock,Java,Concurrency,Thread Safety,Deadlock,嘿,我只想让java开发人员检查我的代码是否是线程安全的,并且没有死锁,因为我想在我的项目中使用它。 Users、UsersByName和UsersByMail是ConcurrentHashMap,字符串、整数作为键,用户对象作为值。UserLocks是一个ConcurrentHashMap,其中整数(显然是用户id作为键)和ReentrantLock作为值。 我想同步这三个哈希映射。 如果有人有一个更好的解决方案来创建一个带有三个键的并发映射,那么在这里发布它会很好。性能也很重要。它是线程安全
ConcurrentHashMap
将提供同步,以避免对同一id使用不同锁的竞争条件
之后,有一段无用的代码,您可以删除:
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();
}
不需要它,因为同步是使用lock.lock()
完成的。不需要再次尝试使用锁对象的wait()
和notify()
与锁对象同步。(实际上,它没有按预期工作,多个线程可以在同一个锁对象上调用lock.isLocked()
,并得到false,直到任何线程调用lock.lock())
,但锁定和解锁之间的所有操作一次只能由一个线程执行)
另外,一个常见的好做法是在finally块中调用
lock.unlock()
。我会使用synchronized
以简单的方式完成
if(lock.isLocked())
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
我想同步这三个HashMap的目的是什么?这三个HashMap的值相同,但键不同。我不希望这样,因为这三个hashmap有不同的值。例如,id、用户名、电子邮件的用户在三个HashMap中表示,现在两个线程想要更新用户,我不希望这三个HashMap具有不同的值。我担心如果两个
user
实体具有相同的id、用户名或电子邮件,但不是所有3个实体都添加到您的映射中,会发生什么?其他地方考虑到了吗?好的,我还有一个问题,使用这些地图来获取用户数据是否有用。我将用户数据保存在mysql数据库中,并在用户登录时检索它们。每当用户进入另一个页面时,这些用户数据都会更新。我应该在后台使用数据库时使用映射并保存应用程序中的更改,还是直接从数据库下载。我想让应用程序尽可能的高性能。因为集合是CHM,如果你只在其中一个集合中查找,你就不需要读锁了,对吗?我怀疑锁的全部意义在于保持3个集合的同步。如果你正在同步(通过同步
或锁
)所有对地图的访问,仅仅使用哈希地图
,不是更有意义吗?@Gray是的,但你可以连续两次读取并获得一个坏名字/电子邮件对。GDPR泄漏的源头就在那里!我同意@OldCurmudgeon。我只是在get*方法中没有看到2个操作,所以我不确定锁在做什么。这就是全部。没什么大不了的。干杯,伙计。
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();
}
}
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();
}
}
}