Java 基于id的线程同步

Java 基于id的线程同步,java,thread-safety,Java,Thread Safety,我需要一种只允许一个线程修改与服务票证相关的数据的方法。可能有多个线程同时试图修改票据数据 下面是我的方法的简化版本。有更好的方法吗?可能使用java.util.concurrent包 public class SomeClass1 { static final HashMap<Integer, Object> ticketLockMap = new HashMap<Integer, Object>(); public void process(int

我需要一种只允许一个线程修改与服务票证相关的数据的方法。可能有多个线程同时试图修改票据数据

下面是我的方法的简化版本。有更好的方法吗?可能使用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;
    }
}
公共类SomeClass1
{
静态最终HashMap ticketLockMap=新HashMap();
公共作废流程(int ticketNumber)
{
已同步(getTicketLock(ticketNumber))
{
//这里只有一个线程可以修改票证数据
//…在这里修改机票。。。
}
}
受保护的静态对象getTicketLock(int ticketNumber)
{
对象ticketLock;
//只允许一个线程使用映射
已同步(ticketLockMap)
{
ticketLock=ticketLockMap.get(ticketNumber);
if(ticketLock==null)
{
//第一次票被锁上了
ticketLock=新对象();
ticketLockMap.put(ticketNumber,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;
}
公共类SomeClass2
{
静态最终HashMap ticketLockMap=新HashMap();
公共作废流程(int ticketNumber)
{
已同步(getTicketLock(ticketNumber))
{
//这里只有一个线程可以修改票证数据
//…在这里修改机票。。。
//进行所有修改后,释放锁
释放ticketlock(ticketNumber);
}
}
受保护的静态锁getTicketLock(int ticketNumber)
{
锁票锁;
//只允许一个线程使用映射
已同步(ticketLockMap)
{
ticketLock=ticketLockMap.get(ticketNumber);
if(ticketLock==null)
{
//第一次票被锁上了
ticketLock=新锁();
ticketLockMap.put(ticketNumber,ticketLock);
}
}
退票锁;
}
受保护的静态无效释放ticketlock(int ticketNumber)
{
//只允许一个线程使用映射
已同步(ticketLockMap)
{
Lock ticketLock=ticketLockMap.get(ticketNumber);
if(ticketLock!=null&--ticketLock.inUseCount==0)
{
//锁不再使用
ticketLockMap.remove(ticketLock);
}
}
}
}
类锁
{
//为简洁起见,省略了构造函数/getter/setter
int inUseCount=1;
}

您可能正在查找。第二种情况可以由a解决,它统计它被锁定的次数

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


然后可以将其与
HashMap
结合使用。您可以省略
synchronized
调用并减少代码行数。

您应该能够使用类似
ConcurrentHashMap
的内容,而不是
HashMap
来执行票证锁,并避免使用性能不佳的
synchronized
putIfAbsent()
应该正是您需要的。@Jeff check this thread@manub ConcurrentHashMap无法处理此问题,因为我们需要对
getTicketLock
releaseTicketLock
方法进行锁定。顺便说一句,在我看到很多糟糕的解决方案后,我认为这种方法已经足够好了,没有条件问题,没有内存泄漏。当锁不再以线程安全的方式使用时,如何确保锁从映射中移除,从而确保映射不会失控?
 Lock l = ...;
 l.lock();
 try {
     // access the resource protected by this lock
 } finally {
     l.unlock();
 }