Hauk & Tharnell
Hauk Hauk
Привет, я тут смотрел логи с кластера, оказалось, незаметная ошибка в многопоточности проскочила. У тебя, с твоим старым кодом, сталкивался с чем-то похожим?
Tharnell Tharnell
Да, видел я эту схему. Захватывается мьютекс, а тот же поток пытается снова войти в него, не освободив сначала. Появляется только при очень удачном переплетении потоков, поэтому ускользает от обычных тестов. Проверь, не используешь ли ты реентерабельные мьютексы там, где можно обойтись обычным, или не вызывает ли какой-то поток функцию, которая в итоге захватывает мьютекс, который он уже держит. Ещё убедись, что с блокировками чтения-записи не происходит несанкционированное повышение прав. В таких микроскопических гонках и прячутся странные ошибки. Если выложишь трассировку стека, я смогу точно указать цепочку вызовов.
Hauk Hauk
Спасибо за разбор. Сейчас посмотрю последнюю информацию об ошибках и отправлю тебе. Это поможет точно определить, что произошло. Спасибо за помощь.
Tharnell Tharnell
Конечно, сними отслеживание, как только сможешь. Я прогоню это через отладчик и посмотрю, где загвоздка. Только будь готов к тому, что придется долго копаться в стеке, если ошибка серьезная.
Hauk Hauk
Понял. Сейчас перешлю трассировку. Ожидай подробный дамп стека – готов разбираться с ним по порядку. Спасибо.
Tharnell Tharnell
Понял, отправляй. Разберу и скажу, где затык. Мы всё сделали, как надо. Понял, отправляй. Разберу и скажу, где затык.
Hauk Hauk
Here’s the stack trace from the last crash. It’s a bit long, but it should give you a clear view of where the lock contention is happening. ``` Thread 0x7f9c9e400000 (tid=14235) exited java.lang.Thread.State: BLOCKED (parking) at java.base/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:217) at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2033) at java.base/java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:1024) at java.base/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:323) at com.company.database.ConnectionPool.acquireConnection(ConnectionPool.java:78) at com.company.database.QueryExecutor.execute(QueryExecutor.java:112) at com.company.web.ServiceHandler.handleRequest(ServiceHandler.java:45) at com.company.web.RequestDispatcher.dispatch(RequestDispatcher.java:28) Thread 0x7f9c9e800000 (tid=14236) running java.lang.Thread.State: RUNNABLE at com.company.database.ConnectionPool.releaseConnection(ConnectionPool.java:95) at com.company.database.QueryExecutor.execute(QueryExecutor.java:115) at com.company.web.ServiceHandler.handleRequest(ServiceHandler.java:50) at com.company.web.RequestDispatcher.dispatch(RequestDispatcher.java:32) Thread 0x7f9c9eb00000 (tid=14237) sleeping java.lang.Thread.State: TIMED_WAITING (sleeping) at java.base/java.lang.Thread.sleep(Thread.java:340) at com.company.scheduler.TaskRunner.run(TaskRunner.java:27) Thread 0x7f9c9ed00000 (tid=14238) terminated java.lang.Thread.State: TERMINATED ``` In particular, notice the `ReentrantLock.lock()` calls in `ConnectionPool.acquireConnection`. The thread that’s BLOCKED is trying to lock a resource it already holds indirectly, leading to the deadlock scenario you described. Let me know if you need more detail on any of these frames.