ОЧІКУВАННЯ на sun.misc.Unsafe.park (рідний метод)


81

Одне з моїх програм зависає під деяким періодом роботи під навантаженням, чи хтось знає, що може спричинити такий вихід у jstack:

"scheduler-5" prio=10 tid=0x00007f49481d0000 nid=0x2061 waiting on condition [0x00007f494e8d0000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006ee117310> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1085)
        at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:807)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1043)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1103)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
        at java.lang.Thread.run(Thread.java:722)

Я багато бачу це у виведенні jstack, коли він зависає.

Я активно використовую Spring @Async та карти, синхронізовані карти та ehcache.

Що цікаво, це відбувається лише в одному з екземплярів програми. Двоє інших працюють абсолютно нормально. Що ще я міг би дослідити, щоб отримати більше деталей у такому випадку?

Я знайшов цю публікацію /programming/23992787/parking-to-wait-for-0xd8cf0070-a-java-util-concurrent-locks-abstractqueueds, але в моєму випадку це не дуже корисно.


2
Це SchedeuledExecutorService, яка буде, waitingмабуть, більшу частину часу. Вам слід шукати ще куди. Очікування тут не споживає процесора, тому не призведе до подальших проблем із продуктивністю.
Джон Вінт,

Якби я був гравцем пари, я б подивився на ваше використання пам’яті та наявність GC.
Джон Вінт,

Добре, дякую. Я увімкнув реєстрацію GC, побачу, що там я можу знайти.
Конрад,

1
@JohnVint Якби ти робив ставку, що б ти підозрював у використанні пам’яті та використанні GC? У мене схожа проблема
user3607022

4
@ користувач3607022 GC Overhead limit reached. Це чітке свідчення того, що у вашої програми є проблеми з пам’яттю. Якщо ви бачите це, це означає, що старе покоління в значній мірі наповнене і не може бути надалі GC'd.
Джон Вінт,

Відповіді:


193

unsafe.park майже те саме, що thread.wait, за винятком того, що він використовує специфічний для архітектури код (отже, причина, по якій він є "небезпечним"). небезпечний не робиться загальнодоступним, але використовується у внутрішніх бібліотеках Java, де специфічний для архітектури код пропонує значні переваги оптимізації. Він багато використовується для об’єднання потоків.

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

Так, я знаю, що ви майже напевно вже вирішили це питання на сьогодні. Тим не менш, ви один з найкращих результатів, якщо хтось погуглить sun.misc.unsafe.park. Я вважаю, що відповідь на запитання може допомогти іншим, хто намагається зрозуміти, що таке цей метод, який, здається, використовує весь їх процесор.


19
І він припаркований, оскільки цей потік є частиною пулу потоків для ExecutorService, і він чекає, поки якесь завдання буде поставлено в чергу роботи за допомогою таких методів, як ExecutorService.submit(...).
Гарольд Л

Чи може це також означати, що він чекає відповіді від з'єднання? Як внутрішній дзвінок?
Nithin Satheesan

@NithinSatheesan, що здається правдоподібним. найкращий спосіб дізнатись - поглянути на стек стека і побачити, хто його викликає.
dsollen

@dsollen Стек стеку такий самий, як і в дописі тут. Він лише починається з Thread.run і закінчується на Unsafe.park.
Nithin Satheesan

9

З трасування стека видно, що потік ThreadPoolExecutor> Worker запустився, і він чекає, поки завдання буде доступне в BlockingQueue (DelayedWorkQueue), щоб вибрати завдання та виконати. Таким чином, цей потік буде у статусі WAIT лише до тих пір, поки отримаєте СИГНАЛ із потоку видавця.


3

У мене була подібна проблема, і після попередніх відповідей (дякую!) Я зміг знайти і знайти, як правильно обробляти припинення роботи ThreadPoolExecutor.

У моєму випадку це просто виправляє моє поступове збільшення подібних заблокованих потоків:

  • Я використав ExecutorService::awaitTermination(x, TimeUnit)і ExecutorService::shutdownNow()(якщо потрібно) у своєму остаточному пункті.
  • Для інформації я використовував наступні команди для виявлення кількості потоків і списку заблокованих потоків:

    ps -u javaAppuser -L | wc -l

    jcmd `ps -C java -o pid =` Thread.print >> threadPrintDayA.log

    jcmd `ps -C java -o pid =` Thread.print >> threadPrintDayAPlusOne.log

    cat threadPrint * .log | grep "pool-" | wc -l

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.