Determine programaticamente qual thread Java contém um bloqueio
-
09-06-2019 - |
Pergunta
É possível em tempo de execução verificar programaticamente o nome do Thread que está mantendo o bloqueio de um determinado objeto?
Solução
Você só pode saber se o thread atual contém um bloqueio normal (Thread.holdsLock(Object)
).Você não pode obter uma referência ao thread que possui o bloqueio sem código nativo.
No entanto, se você estiver fazendo algo complicado com threading, provavelmente desejará se familiarizar com os pacotes java.util.concurrent.O ReentrantLock
permite que você obtenha seu proprietário (mas é um método protegido, então você teria que estender isso).Dependendo da sua aplicação, pode ser que, ao usar os pacotes de simultaneidade, você descubra que, afinal, não precisa obter o proprietário do bloqueio.
Existem métodos não programáticos para localizar os proprietários do bloqueio, como sinalizar a JVM para emitir um dump de encadeamento para stderr, que são úteis para determinar a causa dos conflitos.
Outras dicas
Você pode chegar às fechaduras presas por fios com reflexão.Isso só funciona com java 1.6.
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
ThreadInfo[] ti = bean.getThreadInfo(bean.getAllThreadIds(), true, true);
Em cada um desses objetos ThreadInfo existem objetos LockInfo que você pode usar o IdentityHashCode neles para comparar com o bloqueio em questão.
Você pode, a partir da versão 1.6, usar o JMX para fazer todo tipo de coisas interessantes, incluindo encontrar bloqueios retidos.Você não pode obter o objeto real, mas obtém o valor do hash de classe e identidade (que não é exclusivo).
Correr jconsole.Ele está incluído no Java SDK e é executado na linha de comando.Não tenho certeza de qual sistema operacional você está usando, mas no Windows você pode simplesmente passar o PID do processo Java.Deve ajudá-lo a encontrar o tópico que está causando o problema.Ou você pode usar um criador de perfil comercial como YourKit ou qualquer outro criador de perfil.
Na versão 1.5, você pode encontrar todos os threads e obter o estado de cada um, por exemplo, assim:
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 fornece informações sobre se o thread está BLOQUEADO, ESPERANDO etc., consulte jdk API ThreadState
Você pode verificar o bloqueio de um objeto específico chamando wait()
ou notify()
método nesse objeto.Se o objeto não segurar a trava, ele lançará llegalMonitorStateException
.
2- Ligando holdsLock(Object o)
método.Isso retornará o valor booleano.
se for bloqueio reentrante você pode verificar se ele é mantido pelo thread atual
final ReentrantLock lock = new ReentrantLock();
lock.isHeldByCurrentThread();
Você pode usar uma variável para manter o thread atual ao usar o bloqueio e imprimi-lo se alguém estiver tentando usá-lo.
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;
}
}
Feio, mas funciona.
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);
}
}