当前位置: 首页 > 知识库问答 >
问题:

ReentrantLock.TryLock(长超时,TimeUnit单元)在无法获取锁时不会超时

江曦
2023-03-14

在我的项目与Ehcache集成期间(与BlockingCache装饰器集成,它在内部使用ReentrantLock),我在一台机器上发现了一些奇怪的行为。有时,等待通过ReentrantLock.tryLock(timeout,TimeUnit)-调用大于timeout的时间获取锁的线程不会被超时(结果为“false”)。JVM将它们留在后面,它们被阻塞,直到另一个线程释放这个锁。简而言之:ReentrantLock.tryLock(长超时,TimeUnit单元)的行为与ReentrantLock.Lock()类似。

    null
@Test
public void test() throws Exception {
    System.out.println("debug___");
    int failCount = 0;
    final int REPEAT_TIMES = 50 * 1000;
    for (int i = 0; i < REPEAT_TIMES; i++) {
        System.out.println("");
        try {
            testOne(i);
            System.out.println("debug___" + i + ":ok");
        } catch (Throwable e) {
            failCount++;
            System.err.println(i + ":" + e.getMessage());
            System.out.println(i + ":" + e.getMessage());
            System.out.println("debug___" + i + ":fail");
        }

    }

    System.out.println("fails:" + failCount);
    Assert.assertEquals("Failed " + failCount + "/" + REPEAT_TIMES, 0, failCount);
}

public void testOne(final int i)  throws Exception{
    final StringBuilder sb = new StringBuilder();
    try {
        final ReentrantLock lock = new ReentrantLock();
        final Semaphore s = new Semaphore(0);

        Thread t1 = new Thread() {
            @Override
            public void run() {

                try {
                    sb.append(i + ":" + 1).append("\n");
                    boolean locked = lock.tryLock(1000, TimeUnit.MILLISECONDS);
                    sb.append(i + ":" + 2 + " " + locked).append("\n");
                    s.release();
                    sb.append(i + ":" + 3).append("\n");
                    Thread.sleep(5000); // !!! release lock after 5s
                    sb.append(i + ":" + 4 + " \n");
                    lock.unlock();
                    Thread.sleep(2000);
                } catch (Throwable e) {
                    e.printStackTrace();
                }

            }
        };

        t1.start();
        sb.append(i + ":" + "m1").append("\n");
        s.acquire();
        sb.append(i + ":" + "m2").append("\n");

        long start = System.currentTimeMillis();

        boolean tryLock = lock.tryLock(50, TimeUnit.MILLISECONDS); // try acquire lock for 50ms

        long stop = System.currentTimeMillis();
        long diff = stop - start;

        if (tryLock)
            throw new IllegalStateException("it is really bad.... blocked for a [ms]:" + diff);
    } finally {
        System.out.print(sb.toString());
    }

}

更新

下面是阻止机器的第二个测试:

import java.util.concurrent.locks.*;
import java.util.concurrent.*;

public class TestLock2 {
final ReentrantLock lock = new ReentrantLock();
volatile int inx = 0;

public static void main(String[] a) throws Exception {
    TestLock2 t = new TestLock2();
    t.test();
}

public void log(String s) {
    System.out.println(s);
    System.err.println(s);
}

public void test() throws Exception {
    Thread t1 = new Thread() {
        @Override
        public void run() {
            lock.lock();
            System.out.println("ok");
            while (true) {
                try {
                    Thread.sleep(60 * 1000);
                    log(inx
                            + "                                                     "
                            + new java.util.Date());
                } catch (Exception e) {
                }
            }
        }
    };
    t1.start();
    Thread.sleep(500); // wait for lock to be locked

    System.out.println("debug___");
    int failCount = 0;
    final int REPEAT_TIMES = 20000;
    for (int i = 0; i < REPEAT_TIMES; i++) {
        try {
            inx = i;
            testOne(i);
        } catch (Throwable e) {
            failCount++;
            log(i + ":" + e.getLocalizedMessage());
            log("debug___" + i + ":fail");
        }
    }
    log("Failed " + failCount + "/" + REPEAT_TIMES);
}

public void testOne(final int i) throws Exception {
    long start = System.currentTimeMillis();

    try {
        boolean tryLock = lock.tryLock(200, TimeUnit.MILLISECONDS);
    } finally {
        long diff = System.currentTimeMillis() - start;
        log(i + ":" + diff + "ms");
    }
}

}

“C1 CompilerThread0”后台进程prio=10 tid=0x02b55400 nid=0x7a4正在等待条件[0x00000000]java.lang.Thread.State:可运行

“附加侦听器”后台进程prio=10 tid=0x02b52c00 nid=0x2450等待条件[0x00000000]java.lang.Thread.State:RUNNABLE

“Signal Dispatcher”后台进程prio=10 tid=0x02b51800 nid=0x11d4 runnable[0x00000000]java.lang.Thread.State:runnable

共有1个答案

宋昕
2023-03-14

一种可能的解释可以是,在主进程获得系统时间并且线程将开始Hibernate之后,系统进程调度程序将您的进程从执行中移除。5秒后,继续执行:线程已经Hibernate5秒,主线程获得锁。不过有点奇怪。

无论如何,我建议您使用一个探查器,它将让您看到真正发生了什么。

 类似资料:
  • 我无法使用截击库。我不想无限期地等待请求,所以我不想设置超时。但它不起作用。我在其他地方也有同样的东西(我使用RequestFuture而不是RequestFuture),它运行良好,但在这里我无法将其设置为工作状态。 如果你能提供任何帮助,那就太棒了!谢谢

  • 问题内容: 我的Solr系统(Solr版本3.6.1)有两个核心。当我在专用的Solr服务器上调用以下命令行以添加文件然后为文件建立索引时: 我在文件中得到一个异常(等待大约6分钟后): (您可以在此消息的末尾看到它的详细输出)。 我试图修改锁的超时时间(通过将设置为),但这并不能解决问题。我没有使用任何自定义脚本,而只是使用Solr 3.1.6附带的脚本来添加和编制索引。 关于什么需要更改才能消

  • 我相对来说是android开发的新手。我正在开发一个android应用程序,向web服务器发送请求并解析JSON对象。在与服务器通信时,我经常收到< code > Java . net . socket time out exception:Connection timed out 异常。有时它会完美地工作,没有任何问题。我知道这个问题已经被问过很多次了。但仍然,我没有得到任何满意的解决这个问题的

  • 是否有可能“拦截”会话超时? 我尝试了,但据我所知,当调用HttpSessionListener.session毁灭()'方法时,会话已经被摧毁。(所以我没有机会确定用户,拥有超时的会话) 另一个选项是PhaseListener,在restoreView阶段检查会话是否是“新的”。 但是,我需要在会话超时的“第二天”执行一些操作-不在以后的刷新中执行,也不在以后的登录中执行。 (背景:需要删除某些

  • 问题内容: 我正在尝试在JPA中使用悲观锁定,而不是针对Postgres数据库使用Hibernate 3。我无法超时锁定-它似乎永远挂着。 这是一个例子: 据我了解,em2应该尝试长达五秒钟(5000毫秒)来获取锁,然后应该抛出异常。而是代码陷入僵局。 如果我在两个不同的线程中运行它,那么我会看到线程2(带有em2)在线程1(em1)释放它后立即获得了锁。因此锁定正在发生,只是永不超时。 我用PE

  • 在 HTTP 协议中,当客户端不再处于活动状态时没有显示的终止信号。这意味着当客户端不再处于活跃状态时可以使用的唯一机制是超时时间。 Servlet 容器定义了默认的会话超时时间,且可以通过 HttpSession 接口的 getMaxInactiveInterval 方法获取。开发人员可以使用HttpSession 接口的 setMaxInactiveInterval 方法改变超时时间。这些方法