Hauk & Tharnell
Привет, я тут смотрел логи с кластера, оказалось, незаметная ошибка в многопоточности проскочила. У тебя, с твоим старым кодом, сталкивался с чем-то похожим?
Да, видел я эту схему. Захватывается мьютекс, а тот же поток пытается снова войти в него, не освободив сначала. Появляется только при очень удачном переплетении потоков, поэтому ускользает от обычных тестов. Проверь, не используешь ли ты реентерабельные мьютексы там, где можно обойтись обычным, или не вызывает ли какой-то поток функцию, которая в итоге захватывает мьютекс, который он уже держит. Ещё убедись, что с блокировками чтения-записи не происходит несанкционированное повышение прав. В таких микроскопических гонках и прячутся странные ошибки. Если выложишь трассировку стека, я смогу точно указать цепочку вызовов.
Спасибо за разбор. Сейчас посмотрю последнюю информацию об ошибках и отправлю тебе. Это поможет точно определить, что произошло. Спасибо за помощь.
Конечно, сними отслеживание, как только сможешь. Я прогоню это через отладчик и посмотрю, где загвоздка. Только будь готов к тому, что придется долго копаться в стеке, если ошибка серьезная.
Понял. Сейчас перешлю трассировку. Ожидай подробный дамп стека – готов разбираться с ним по порядку. Спасибо.
Понял, отправляй. Разберу и скажу, где затык. Мы всё сделали, как надо. Понял, отправляй. Разберу и скажу, где затык.
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.