如何在这种情况下添加锁?

时间:2011-11-21 14:11:16

标签: java multithreading

像这样的代码......

public void beforeUpdated(Log log){
    synchronized(this){
       query(log);
       merge(log);
       persist(log);
    }
}

此方法在多线程环境下运行。日志的CRUD必须是原子操作。但只需要同步相同id的日志(log.getUuid())。如果我锁定所有操作,它必须表现不佳。我只希望同一个id的日志在原子操作下锁定。我该怎么做?如果你有任何想法,请帮帮我。谢谢。

3 个答案:

答案 0 :(得分:5)

我遇到过这种情况几次。你需要的是一个单独的LockFactory,它实际上是一个锁对象弱引用的字典。代码应该是这样的:

class LockFactory {
    private LockFactory() {}
    private LockFactory instance = null;
    public static LockFactory getInstance() { 
        if (this.instance == null)
            this.instance = new LockFactory();
        return this.instance;
    }
    private int _last_check_size = 0;
    private int _cleanup_size = 1000;
    private Map<String, WeakReference> weakRefDictionary = new HashMap<String, WeakReference>();
    public object getLock(String id) {
        synchronized(this) {
             if (!this.weakRefDictionary.containsKey(id))
                 this.weakRefDictionary.put(id, new WeakReference(null));
             Object lock = this.weakRefDictionary.get(id).Target;
             if (lock == null) { 
                lock = new Object();
                this.weakRefDictionary.get(id).Target = lock;
             }
             if (this.weakRefDictionary.size() > this._last_check_size + this._cleanup_size)
                  this._do_cleanup();
             return lock;
        }
    }
    public void _do_cleanup() {
        synchronized(this) {
            Iterator<Map.Entry<String, WeakReference>> iter = this.weakRefDictionary.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry<String,WeakReference> entry = iter.next();
                if (entry.getValue().get() == null) {
                    iter.remove();
                }
            }
            this._last_check_size = this.weakRefDictionary.size();
        }
    }
}

现在在你的情况下使用:

public void beforeUpdated(Log log){
    synchronized(LockFactory.getInstance().getLock(log.getUuid())){
       query(log);
       merge(log);
       persist(log);
    }
}

答案 1 :(得分:1)

您可以维护一个HashMap,将迄今为止遇到的日志ID映射到某些Object,并在属于正在写入的日志的id的Object上进行同步至。请注意,必须在HashMap本身上同步对HashMap的读取和写入。

答案 2 :(得分:0)

一个建议是做类似的事情:

class Log
{
    private static final WeakHashMap<String, Object> LOCKS = 
        new WeakHashMap<String, Object>();

    private final String uuid;

    public Log(String uuid)
    {
        this.uuid = uuid;
    }

    public Object getLock()
    {
        synchronized (LOCKS)
        {
            Object lock = LOCKS.get(uuid);
            if (lock == null)
            {
                lock = new Object();
                LOCKS.put(uuid, lock);
            }
            return lock;
        }
    }
}

并将其用作:

public void beforeUpdated(Log log) 
{
    synchronized (log.getLock()) 
    {
       query(log);
       merge(log);
       persist(log);
    }
}

如果从静态弱映射获取锁定的瓶颈困扰您,您可以尝试使用Guava MapMaker之类的东西构建并发弱哈希映射。