Дедлок, вызванный thread.join () в статическом блоке - PullRequest
1 голос
/ 14 июля 2011

Я столкнулся с тупиковым сценарием, который можно обобщить как класс StaticDeadlock, показанный ниже.

Эта простая программа остановится на o.getClass () . Вот мое предположение о том, что произошло, но кто-то может объяснить это лучше?

1) программа входит в статический блок StaticDeadlock

2) Тема Запускается

3) основной поток находится в ожидании завершения потока , следовательно, не может завершить статический блок

4) внутри поток доступ к StaticDeadlock.o , но статический блок StaticDeadlock еще не завершен. Значит программа зависает?

    public class StaticDeadlock
    {
        private static final Object o = new Object();

        static {
            MyThread thread = new MyThread();
            thread.start();

            try {
                thread.join();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public static void main (String[] args)
        {
            System.out.println("all is well.");
        }

        static class MyThread extends Thread
        {
            @Override
            public void run ()
            {
                System.out.println("inside mythread");
                o.getClass();
            }
        }

    }

1 Ответ

8 голосов
/ 14 июля 2011

Да, вот и все. Новый поток ожидает завершения инициализатора класса StaticDeadlock, прежде чем он получит доступ к статическому члену. См. раздел 12.4.2 Спецификации языка Java для получения более подробной информации, в частности, эти шаги:

  1. Синхронизация (§14.19) на объекте Class, который представляет класс или интерфейс для инициализации. Это включает ожидание, пока текущий поток не сможет получить блокировку для этого объекта (§17.1).

  2. Если для класса или интерфейса выполняется инициализация какого-либо другого потока, подождите, пока этот объект класса (который временно снимает блокировку). Когда текущий поток пробуждается от ожидания, повторите этот шаг.

  3. Если текущий класс выполняет инициализацию для класса или интерфейса, то это должен быть рекурсивный запрос на инициализацию. Снимите блокировку с объекта Class и завершите ее обычным образом.

  4. Если класс или интерфейс уже инициализированы, дальнейшие действия не требуются. Снимите блокировку с объекта Class и завершите ее обычным образом.

Он даже не пройдет шаг 1 во втором потоке, так как первый поток имеет блокировку и не снимает ее.

Обратите внимание, что это не вызывает getClass(), что вызывает проблему - выполнение что-либо , для которого требуется значение o, заставит второй поток ждать, пока инициализатор класса завершит работу, что, конечно, выиграло ' Это происходит потому, что первый поток ожидает завершения второго потока.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...