Программно определить, какой поток Java удерживает блокировку

Возможно ли во время выполнения программно проверить имя потока, который удерживает блокировку данного объекта?

Измените заголовок и сообщение, указав, что вы имеете в виду Java. Тег не должен быть единственным местом, где размещается важная информация, относящаяся к вопросу.

Adam Davis 09.09.2008 00:24
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
43
1
23 078
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Ответ принят как подходящий

Вы можете только определить, имеет ли текущий поток нормальную блокировку (Thread.holdsLock(Object)). Вы не можете получить ссылку на поток с блокировкой без собственного кода.

Однако, если вы делаете что-нибудь сложное с потоками, вы, вероятно, захотите ознакомиться с пакетами java.util.concurrent. ReentrantLock позволяет вам получить своего владельца (но это защищенный метод, поэтому вам придется его расширить). В зависимости от вашего приложения вполне может оказаться, что, используя пакеты параллелизма, вы обнаружите, что вам все-таки не нужно получать владельца блокировки.

Существуют непрограммные методы поиска владельцев блокировок, такие как сигнализация JVM о выдаче дампа потока в stderr, которые полезны для определения причины взаимоблокировок.

Запустите jconsole. Он включен в Java SDK и запускается из командной строки. Я не уверен, какую ОС вы используете, но в Windows вы можете просто передать ей PID процесса Java. Это должно помочь вам найти нить, которая вызывает проблему. Или вы можете использовать коммерческий профилировщик, такой как YourKit, или любое количество других профилировщиков.

Начиная с версии 1.6, вы можете использовать JMX для выполнения всевозможных интересных вещей, включая поиск заблокированных блокировок. Вы не можете получить фактический объект, но вы получите хеш-значение класса и идентификатора (которое не является уникальным).

В одном из моих блогов есть пример.

В 1.5 вы можете найти все потоки и получить состояние каждого, например, вот так:

    Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
    for (Map.Entry<Thread, StackTraceElement[]> threadEntry : map.entrySet()) {
        log.info("Thread:"+threadEntry.getKey().getName()+":"+threadEntry.getKey().getState());
        for (StackTraceElement element : threadEntry.getValue()) {
            log.info("--> "+element);
        }
    }

Thread.getState дает вам информацию о том, заблокирован ли поток, ОЖИДАЕТСЯ и т. д., См. jdk api ThreadState

Вы можете добраться до замков, удерживаемых потоками с отражением. Это работает только с java 1.6.

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] ti = bean.getThreadInfo(bean.getAllThreadIds(), true, true);

На каждом из этих объектов ThreadInfo есть объекты LockInfo, которые вы можете использовать с помощью identityHashCode для сравнения с рассматриваемой блокировкой.

Вы можете использовать переменную, чтобы удерживать текущий поток, когда вы берете блокировку, а затем распечатывать ее, если кто-то пытается ее использовать.

Thread holderOfLock = null;
Object theLock = new Object();

public void doStuff()
{
    if (holderOfLock != null)
    {
       //get and print name of holderOfLock-thread or get stacktrace etc.
    }

    synchronized (theLock)
    {
        holderOfLock = Thread.currentThread();
        //do stuff...
        holderOfLock = null;
    }
}

Вы можете проверить блокировку конкретного объекта, вызвав метод wait() или notify() для этого объекта. Если объект не удерживает блокировку, он выбрасывает llegalMonitorStateException.

2- Вызов метода holdsLock(Object o). Это вернет логическое значение.

если это блокировка с повторным входом, вы можете проверить, удерживается ли он текущим потоком

final ReentrantLock lock = new ReentrantLock();
lock.isHeldByCurrentThread();

Уродливо, но работает.

String findLockOwner(ReentrantLock lock) {
    String patternStr = "\[Locked by thread (\S+)\]";
    Pattern pattern = Pattern.compile(patternStr);
    Matcher matcher = pattern.matcher(lock.toString());
    boolean matchFound = matcher.find();
    if (matchFound && matcher.groupCount() >= 1) {
      return matcher.group(1);
    }
}

Другие вопросы по теме