简体   繁体   English

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

[英]Will this method work thread-safe and without Deadlocks

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();
}

Hey, I just want to ask the java developers to check my code if it will be thread-safe and free of Deadlocks as I want to use it in my project. 嘿,我只想请Java开发人员检查我的代码是否是线程安全的,并且没有死锁,因为我想在项目中使用它。 Users, UsersByName and UsersByEmail are ConcurrentHashMap with String, Integer as key and User object as Value. Users,UsersByName和UsersByEmail是ConcurrentHashMap,其中String,Integer作为键,User对象作为Value。 UserLocks is a ConcurrentHashMap with Integer (obviously the user id as key) and a ReentrantLock as value. UserLocks是一个带有Integer(显然是用户ID作为键)和ReentrantLock作为值的ConcurrentHashMap。 I want to synchronize the three HashMaps. 我想同步三个HashMap。 If someone has a better solution to make a Concurrent map with three keys, it would be nice to post it here. 如果有人有更好的解决方案来制作带有三个键的并发地图,最好在此处发布。 Performance is also important. 性能也很重要。

It's thread safe. 这是线程安全的。

If the userId is already in the map, the code gets the lock and use it to synchronize. 如果userId已经在映射中,则代码获取锁并使用它进行同步。 If not, ConcurrentHashMap provides the syncronization to avoid a race condition to use different locks for the same id. 如果没有, ConcurrentHashMap提供同步功能,以避免争用条件为同一id使用不同的锁。

Afterthat, there is a useless fragment of code, you can get rid off: 之后,有一段无用的代码片段,您可以摆脱掉:

if(lock.isLocked())
    try {
        lock.wait();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

It's not needed because the synchronization is being done using lock.lock() . 不需要,因为同步是使用lock.lock() It's not needed to try to synchronize again using wait() and notify() with the lock object.(Actually, it is not working as you expected, several threads can call lock.isLocked() on the same lock object and get a false until any of the threads calls lock.lock() , but everything between lock and unlock is only being executed by a single Thread at a time). 不需要尝试使用wait()notify()与锁对象再次进行同步。(实际上,它没有按预期工作,几个线程可以在同一个锁对象上调用lock.isLocked()并得到false直到任何一个线程调用lock.lock() ,但锁定和解锁之间的所有操作一次只能由单个线程执行)。

Also, an usual good practice is to call the lock.unlock() in a finally block. 另外,通常的良好做法是在finally块中调用lock.unlock()

I would do it the simple way using synchronized . 我会使用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();
    }
}

This would ensure that all maps are updated consistently so long as all of your getters are also synchronized . 只要您的所有getter也都synchronized ,这将确保所有地图都一致更新。

If, however, you want better performance and want to avoid making all of your methods synchronized then use a ReadWriteLock . 但是,如果您想要更好的性能,并且希望避免所有方法都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();
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM