Java 此方法是否可以在线程安全且无死锁的情况下工作

Java 此方法是否可以在线程安全且无死锁的情况下工作,java,concurrency,thread-safety,deadlock,Java,Concurrency,Thread Safety,Deadlock,嘿,我只想让java开发人员检查我的代码是否是线程安全的,并且没有死锁,因为我想在我的项目中使用它。 Users、UsersByName和UsersByMail是ConcurrentHashMap,字符串、整数作为键,用户对象作为值。UserLocks是一个ConcurrentHashMap,其中整数(显然是用户id作为键)和ReentrantLock作为值。 我想同步这三个哈希映射。 如果有人有一个更好的解决方案来创建一个带有三个键的并发映射,那么在这里发布它会很好。性能也很重要。它是线程安全

嘿,我只想让java开发人员检查我的代码是否是线程安全的,并且没有死锁,因为我想在我的项目中使用它。 Users、UsersByName和UsersByMail是ConcurrentHashMap,字符串、整数作为键,用户对象作为值。UserLocks是一个ConcurrentHashMap,其中整数(显然是用户id作为键)和ReentrantLock作为值。 我想同步这三个哈希映射。 如果有人有一个更好的解决方案来创建一个带有三个键的并发映射,那么在这里发布它会很好。性能也很重要。

它是线程安全的

如果用户ID已经在映射中,代码将获得锁并使用它进行同步。否则,
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();
        }
    }
}