Bug:StampedLock的中斷問題導致CPU爆滿

StampedLock作爲JAVA8中出現的新型鎖,很可能在大多數場景都可以替代ReentrantReadWriteLock。它對於讀/寫都提供了四個接口(換成write爲寫鎖):

  • readLock()
  • tryReadLock()
  • tryReadLock(long time, TimeUnit unit)
  • readLockInterruptibly()
這幾個方法對應的語義爲:
  • 獲取讀鎖(阻塞,不響應中斷)
  • 獲取讀鎖(立即)
  • 限時獲取讀鎖(響應中斷)
  • 獲取讀鎖(阻塞,響應中斷)
然而在readLock方法(即不響應中斷)中存在嚴重問題(write的版本也是),觀察CPU使用率,執行以下代碼:
public class TestStampedLock {
    public static void main(String[] args) throws InterruptedException{
        final StampedLock lock = new StampedLock();
        new Thread(){
            public void run(){
                long readLong = lock.writeLock();
                LockSupport.parkNanos(6100000000L);
                lock.unlockWrite(readLong);
            }
        }.start();
        Thread.sleep(100);
        for( int i = 0; i < 3; ++i)
            new Thread(new OccupiedCPUReadThread(lock)).start();
    }
    private static class OccupiedCPUReadThread implements Runnable{
        private StampedLock lock;
        public OccupiedCPUReadThread(StampedLock lock){
            this.lock = lock;
        }
        public void run(){
            Thread.currentThread().interrupt();
            long lockr = lock.readLock();
            System.out.println(Thread.currentThread().getName() + " get read lock");
            lock.unlockRead(lockr);
        }
    }
}
先開啓一個線程獲取寫鎖並保持6秒,再開啓三個帶着中斷狀態的線程去獲取讀鎖(readLock方法),結果是3個核心被佔據了近6秒。
原因在於沒有使用保存/復原中斷狀態的機制,通過hack源碼,插入保存中斷和返回前恢復中斷的相關代碼即可修復:
boolean interrupted = false;
if(interrupted)
                                    Thread.currentThread().interrupt();
                                return ns;
if(Thread.interrupted()){
                            if(interruptible)
                                return cancelWaiter(node, p, true);
                            else
                                interrupted = true;
                        }



StampedLock

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章