美文网首页
StampedLock 在JDK1.8 中的bug

StampedLock 在JDK1.8 中的bug

作者: 程序员札记 | 来源:发表于2022-04-06 09:26 被阅读0次

StampedLock其内部是通过死循环+CAS操作的方式来修改状态位,在挂起线程时,是通过unsafe.park的方式,而对于中断的线程,unsafe.park会直接返回,而在StampedLock的死循环逻辑中,没有处理中断的逻辑,就会导致阻塞在park上的线程中断后,再次进入循环,直到当前死循环满足退出条件,因此整个过程会使cpu暴涨。

这里面有个java 线程的基本知识, 正常的线程循环被调用interrupt 后,本身并不会退出, 而仅仅是线程设置了一个interrupted的标记为,当有次标记位后,park 就不会起作用。 因此线程堵塞就失败了。

下面看一段测试代码

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

github上 有人尝试StampedLock.java类的修改:https://github.com/zuai/Hui/blob/master/StampedLock.java

从修改的代码上看,我觉得并不合适。参考AQS的实现, 我的理解是如果 acquireWrite 或者 acquireWrite 本身发生中断时需要和acquireQueued 一样的处理,在park 方法加一个额外的判断,通过Thread.interrupted() 来进行中断标记清除

                     if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
                        whead == h && node.prev == p )
                          parkAndCheckInterrupt()
         
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();
    }

如果需要抛出中断异常, 则需要增加acquireWriteInterruptibly 和acquireWriteInterruptibly 两个接口方法代码类似改成如下

                     if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
                        whead == h && node.prev == p )
                          if(parkAndCheckInterrupt(){
                                throw new InterruptedException();
                          }

相关文章

网友评论

      本文标题:StampedLock 在JDK1.8 中的bug

      本文链接:https://www.haomeiwen.com/subject/fbcrsrtx.html