首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >条形ReadWriteLock抛出IllegalMonitorStateException -试图解锁读取锁,而不是被当前线程锁定

条形ReadWriteLock抛出IllegalMonitorStateException -试图解锁读取锁,而不是被当前线程锁定
EN

Stack Overflow用户
提问于 2022-11-29 07:06:30
回答 1查看 46关注 0票数 1

我们正在编写一个并发的multimap,以便在多线程应用程序中存储相同密钥的多个值。我们已经扩展了番石榴ForwardingMultimap来做同样的事情。Put和remove方法获取密钥上的写锁,并在最后释放它。类似地,获取密钥上的读锁并在结束时释放它。我已经通过在本地系统中使用多个线程来测试这一点,而且它工作得很好。

现在问题在于clear方法,如果一个线程正在执行put/remove,而另一个线程执行清除,那么就会出现不一致性。为了解决这个问题,我们用清晰的方法决定在公钥上添加一个写锁,并在最后发布它。类似地,put和remove方法也得到了改进,在公钥上有一个读锁,并在最后释放它。就像下面这样。

代码语言:javascript
复制
IResourceLockManager mLocks = new ResourceLockManager();
private final String mPublicKey = "$public";
private final int mLockTimeOut = 0;

放置/删除操作

代码语言:javascript
复制
public boolean put(Object aKey, Object aValue) {
   mLocks.acquireReadLock(mPublicKey, mLockTimeOut);
   mLocks.acquireWriteLock(aKey, mLockTimeOut);
   boolean result = false;
   try {
      result = delegate().put(aKey, aValue);
   } finally {
      mLocks.releaseWriteLock(aKey);
      mLocks.releaseReadLock(mPublicKey);
   }
   return result;
}

清除行动

代码语言:javascript
复制
public void clear() {
   mLocks.acquireWriteLock(mPublicKey, mLockTimeOut);
   try {
      delegate().clear();
   } finally {
      mLocks.releaseWriteLock(mPublicKey); 
   }
}

ResourceLockManager码

代码语言:javascript
复制
Striped<ReadWriteLock> lockCache = Striped.lazyWeakReadWriteLock(DEFAULT_PARTITIONS);

acquireReadLock

代码语言:javascript
复制
lockCache.get(aKey).readLock().lock()

releaseReadLock

代码语言:javascript
复制
lockCache.get(aKey).readLock().unlock();

acquireWriteLock

代码语言:javascript
复制
lockCache.get(aKey).writeLock().lock()

releaseWriteLock

代码语言:javascript
复制
lockCache.get(aKey).writeLock().unlock();

在实现了公钥的读/写锁以处理清楚的方法情况后,我开始面临以下问题:

代码语言:javascript
复制
Exception in thread "pool-5-thread-10" java.lang.IllegalMonitorStateException: attempt to unlock read lock, not locked by current thread
    at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.unmatchedUnlockException(ReentrantReadWriteLock.java:444)
    at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(ReentrantReadWriteLock.java:428)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared(AbstractQueuedSynchronizer.java:1341)
    at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.unlock(ReentrantReadWriteLock.java:881)
    at com.google.common.util.concurrent.ForwardingLock.unlock(ForwardingLock.java:48)
    at org.multimap.rt.locks.ResourceLockManager.releaseReadLock(ResourceLockManager.java:97)
    at org.multimap.rt.util.ConcurrentMultiMap.put(ConcurrentMultiMap.java:81)
    at org.multimap.rt.util.OneShotTask.run(ConcurrentMultiMapTest.java:233)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

上面的问题不仅是为了放,它有时也是在移除期间,它不是总是来的。就好像每3-4次就有一次。

另一个观察-为了测试并发性,如果我们创建了44个或更少的线程,那么我就不会在本地系统中看到这个问题。一到45岁或更多,我就开始看到这个例外。

单元测试代码:

代码语言:javascript
复制
   public void TestConcurrentMultiMap() throws InterruptedException {
      ExecutorService executor = Executors.newFixedThreadPool(45);
      for (int i = 0; i < 45; i++) {
         int num = (int) Math.round(Math.floor(Math.random() * 3));
         int oprn = (int) Math.round(Math.random());
         executor.execute(new OneShotTask(String.valueOf(num), myMap1, oprn));
      }
      executor.shutdown();
      executor.awaitTermination(1000L, TimeUnit.MILLISECONDS);
   }

class OneShotTask implements Runnable {
   String str;
   Multimap mMap;
   int mOprn;

   OneShotTask(String s, Multimap aMap, int oprn) {
      str = s;
      mOprn = oprn;
      mMap = aMap;
   }
   public void run() {
      try {
         Thread.sleep(100);
       } catch (InterruptedException e) {
         throw new RuntimeException(e);
       }
       if(mOprn == 0) {
          mMap.put("key", "value" + str );
       } else { 
          mMap.remove("key", "value" + str ); 
      }
   }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-12-02 10:00:59

看起来Striped.lazyWeakReadWriteLock()中有一个bug。通过将初始化从Striped.lazyWeakReadWriteLock更改为Striped.readWriteLock(),我无法再现它。

这里有更多的细节- https://github.com/google/guava/issues/2477

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74610227

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档