4

I need a way to allow only one thread to modify data related to a service ticket. More than one thread may be attempting to modify the ticket data at the same time.

Below is a simplified version of my approach. Is there a better way to do this? Maybe with java.util.concurrent packages?

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

Additionally, if I don't want the HashMap filling up with unused locks, I would need a more complex approach like the following:

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;
}
4

1 回答 1

1

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

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

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

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

于 2016-03-30T14:47:30.287 回答