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

问题描述 投票:1回答:2
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地图,那么在此处发布它会很不错。表现也很重要。

java concurrency thread-safety deadlock
2个回答
1
投票

这是线程安全的。

如果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块。


1
投票

我会用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();
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.