基于id的线程同步

时间:2013-06-12 15:34:54

标签: java thread-safety

我需要一种方法来只允许一个线程修改与服务票证相关的数据。多个线程可能正在尝试同时修改故障单数据。

以下是我的方法的简化版本。有一个更好的方法吗?也许用java.util.concurrent包?

public class SomeClass1
{
    static final HashMap<Integer, Object> ticketLockMap = new HashMap<Integer, Object>();


    public void process(int ticketNumber)
    {
        synchronized (getTicketLock(ticketNumber))
        {
            // only one thread may modify ticket data here

            // ... ticket modifications here...
        }
    }


    protected static Object getTicketLock(int ticketNumber)
    {
        Object ticketLock;

        // allow only one thread to use map
        synchronized (ticketLockMap)
        {
            ticketLock = ticketLockMap.get(ticketNumber);

            if (ticketLock == null)
            {
                // first time ticket is locked
                ticketLock = new Object();
                ticketLockMap.put(ticketNumber, ticketLock);
            }
        }

        return ticketLock;
    }
}

此外,如果我不希望HashMap填满未使用的锁,我需要一个更复杂的方法,如下所示:

public class SomeClass2
{
    static final HashMap<Integer, Lock> ticketLockMap = new HashMap<Integer, Lock>();


    public void process(int ticketNumber)
    {
        synchronized (getTicketLock(ticketNumber))
        {
            // only one thread may modify ticket data here

            // ... ticket modifications here...

            // after all modifications, release lock
            releaseTicketLock(ticketNumber);
        }
    }


    protected static Lock getTicketLock(int ticketNumber)
    {
        Lock ticketLock;

        // allow only one thread to use map
        synchronized (ticketLockMap)
        {
            ticketLock = ticketLockMap.get(ticketNumber);

            if (ticketLock == null)
            {
                // first time ticket is locked
                ticketLock = new Lock();
                ticketLockMap.put(ticketNumber, ticketLock);
            }
        }

        return ticketLock;
    }


    protected static void releaseTicketLock(int ticketNumber)
    {
        // allow only one thread to use map
        synchronized (ticketLockMap)
        {
            Lock ticketLock = ticketLockMap.get(ticketNumber);

            if (ticketLock != null && --ticketLock.inUseCount == 0)
            {
                // lock no longer in use
                ticketLockMap.remove(ticketLock);
            }
        }
    }
}


class Lock
{
    // constructor/getters/setters omitted for brevity
    int inUseCount = 1;
}

1 个答案:

答案 0 :(得分:1)

您可能正在寻找Lock interface。第二种情况可以通过ReentrantLock来解决,它计算锁定的次数。

锁有一个等待锁获取的.lock()方法和一个应该被调用的.unlock方法

 Lock l = ...;
 l.lock();
 try {
     // access the resource protected by this lock
 } finally {
     l.unlock();
 }

然后可以将其与HashMap<Integer, Lock>结合使用。您可以省略synchronized次调用并减少代码行。