From 51d8ff6d6c8bbf08dbf6838d3e9d5431cbce2db8 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 14 Feb 2023 10:10:48 +0100 Subject: [PATCH] [Minor] Extended LockableObject to log owner of locks on lock timeout --- .../xmlpers/objref/LockableObject.java | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java b/xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java index 0154a3daa..ca854d646 100644 --- a/xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java +++ b/xmlpers/src/main/java/li/strolch/xmlpers/objref/LockableObject.java @@ -20,11 +20,10 @@ import static java.text.MessageFormat.format; import static li.strolch.utils.helper.StringHelper.formatMillisecondsDuration; import java.text.MessageFormat; -import java.util.Map; +import java.util.Collection; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; -import li.strolch.utils.helper.StringHelper; import li.strolch.xmlpers.api.XmlPersistenceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,12 +37,12 @@ public class LockableObject { LockableObject.tryLockTime = tryLockTime; } - private final ReentrantLock lock; + private final Lock lock; protected final String name; public LockableObject(String name) { this.name = name; - this.lock = new ReentrantLock(true); + this.lock = new Lock(true); } public String getName() { @@ -69,19 +68,21 @@ public class LockableObject { String msg = "Thread {0} failed to acquire lock after {1} for {2}"; //$NON-NLS-1$ msg = format(msg, currentThread().getName(), formatMillisecondsDuration(tryLockTime), this); - try { - logger.error(msg); - logger.error("Listing all active threads: "); - Map allStackTraces = Thread.getAllStackTraces(); - for (Thread thread : allStackTraces.keySet()) { - StackTraceElement[] trace = allStackTraces.get(thread); - StringBuilder sb = new StringBuilder(); - for (StackTraceElement traceElement : trace) - sb.append("\n\tat ").append(traceElement); - logger.error("\nThread " + thread.getName() + ":\n" + sb.toString() + "\n"); - } - } catch (Exception e) { - logger.error("Failed to log active threads: " + e.getMessage(), e); + Thread owner = lock.getOwner(); + if (owner == null) { + logger.error(MessageFormat.format("Lock {0} is currently held unknown thread!", this.name)); + logger.error(lock.toString()); + } else { + Exception e = new Exception(); + e.setStackTrace(owner.getStackTrace()); + logger.error(MessageFormat.format("Lock {0} is currently held by {1}", this.name, owner), e); + } + + logger.error("Threads waiting on this lock are:"); + for (Thread queuedThread : lock.getQueuedThreads()) { + Exception e = new Exception(); + e.setStackTrace(queuedThread.getStackTrace()); + logger.error("\n" + queuedThread.getName(), e); } throw new XmlPersistenceException(msg); @@ -103,4 +104,21 @@ public class LockableObject { this.lock.unlock(); } } + + public static class Lock extends ReentrantLock { + + public Lock(boolean fair) { + super(fair); + } + + @Override + public Thread getOwner() { + return super.getOwner(); + } + + @Override + public Collection getQueuedThreads() { + return super.getQueuedThreads(); + } + } }