Возможно ли для нити сам Deadlock? - PullRequest
56 голосов
/ 16 августа 2010

Технически возможно, чтобы поток в Java самоблокировался?

Меня спросили об этом на собеседовании некоторое время назад, и он ответил, что это невозможно, но интервьюер сказал мне, что это так.К сожалению, я не смог получить его метод о том, как добиться этого тупика.

Это заставило меня задуматься, и единственная ситуация, о которой я могу подумать, это то, где вы можете сделать это, когда у вас есть сервер RMI.Процесс, который содержит метод, который вызывает себя.Строка кода, вызывающая метод, помещается в синхронизированный блок.

Возможно ли это или же интервьюер неверен?

Исходный код, о котором я думал, был по этим направлениям (гдеtestDeadlock выполняется в процессе сервера RMI)

public boolean testDeadlock () throws RemoteException {
    synchronized (this) {
        //Call testDeadlock via RMI loopback            
    }
}

Ответы [ 20 ]

1 голос
/ 08 ноября 2010

Вы можете завести себя в однопоточный тупик с помощью ReentrantReadWriteLock .Блокировки записи могут получить блокировки чтения, но не наоборот.Следующее будет заблокировано на неопределенный срок.

    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    lock.readLock().lock();
    lock.writeLock().lock();
1 голос
/ 16 августа 2010

Нет, потому что Java реализует reentrancy .Но, пожалуйста, не путайте параллелизм и RMI.Синхронизация в заглушках - это нечто совершенно иное, чем удаленные объекты, которые внутренне синхронизированы.

0 голосов
/ 16 августа 2010

Когда поток входит в синхронизированный блок, он проверяет, является ли текущий поток владельцем блокировки, и если это так, поток просто продолжается без ожидания.

Так что я не думаю, что это возможно.

0 голосов
/ 16 августа 2010

Если вы расширите определение термина взаимоблокировка: один поток может оказаться заблокированным для одноразовой блокировки, которую он взял ранее.

0 голосов
/ 16 августа 2010

В идеале поток никогда не должен сам создавать взаимоблокировку, используя «синхронизированные блокировки», если только в самой JVM действительно нет ошибки, как «якобы» заметил некоторыми людьми в более старых версиях

0 голосов
/ 31 августа 2012

Я знаю, что это старый пост.Вот еще один пример того, как это может произойти, если ваш код взаимодействует с внешними ресурсами:

У меня есть поток, который открывает соединение с базой данных, запускает транзакцию A и начинает обновление.Тот же поток, откройте другое соединение, запустите другую транзакцию.Тем не менее, поскольку транзакция A еще не зафиксирована и заблокирована таблица базы данных, транзакция B получает доступ к этой заблокированной таблице, поэтому ей приходится ждать

более одного соединения с базой данных.


Это часто происходило в приложении, с которым я работаю, потому что в приложении много модулей, и поток может запускаться несколькими способами.Эти методы открывают свои собственные соединения.Поскольку у нас разные разработчики писали свой код, они могут не видеть, как начинается их код, и поэтому не могли видеть общие транзакции базы данных, открытые приложением.

0 голосов
/ 29 декабря 2013

Интервьюер был прав. Поток может заблокировать себя согласно JCIP . Но как?

В разделе 2.3.2 JCIP у нас есть следующий параграф о Reentrancy:

Повторный вход облегчает инкапсуляцию поведения блокировки, и тем самым упрощает разработку объектно-ориентированной concurrentcode. Без повторных входов очень естественный код в Листинге 2.7, в котором подкласс переопределяет синхронизированный метод, а затем вызывает метод суперкласса, будет тупик.

Блокировка синхронизированного ключевого слова - это блокировка повторного входа, поэтому поток может блокировать и разблокировать вложенным способом, но если вы используете блокировку без повторного входа, как в следующем примере, который я написал в качестве доказательства. У вас будет тупик! Согласно JCIP.

public class SelfDeadLock {


    public static class Father{
        volatile protected int n = 0;
        protected Lock ourLock = new Lock();

        public void writeSth(){
            try {
                ourLock.lock();
                n++;
                System.out.println("Father class: " + n);
            } catch (InterruptedException ex) {
                Logger.getLogger(SelfDeadLock.class.getName()).log(Level.SEVERE, null, ex);
            }
            ourLock.unlock();
        }
    }

    public static class Child extends Father{

        @Override
        public void writeSth() {
            try {
                ourLock.lock();
                n++;
                System.out.println("Child class: " + n);
                super.writeSth();
            } catch (InterruptedException ex) {
                Logger.getLogger(SelfDeadLock.class.getName()).log(Level.SEVERE, null, ex);
            }
            ourLock.unlock();
        }   
    }

    public static void main(String[] args) {
        Child child = new Child();
        child.writeSth();
    }
}
0 голосов
/ 16 августа 2010

Вот способ, которым поток может заблокировать себя.

public class DeadlockMe
{
    public static void main(String[] args)
    {
        DeadlockThing foo = new DeadlockThing();
        synchronized(foo)
        {
            try
            {
                foo.wait();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
}

Поток создает экземпляр класса - любой класс и ожидает его. Поскольку поток создал объект с локальной областью действия, у любого другого потока нет никакого способа уведомить объект о пробуждении потока.

0 голосов
/ 04 марта 2019

Хотя комментарии здесь педантичны по поводу "тупика", возникающего, если по крайней мере два потока / действия конкурируют за один и тот же ресурс ... Я думаю, что дух этого вопроса заключался в обсуждении необходимости блокировки реентранта, особенно в контексте«рекурсивной» блокировки

Вот пример в python (я уверен, что концепция остается неизменной в Java): если вы измените RLock на Lock (то есть, повторно входящая блокировка для блокировки, поток будет зависать)

import threading

"""
Change RLock to Lock to make it "hang"
"""
lock = threading.Condition(threading.RLock())


def print_list(list):
    lock.acquire()
    if not list:
        lock.release()
        return
    print(list[0])
    print_list(list[1:])
    lock.release()


print_list([1, 2, 3, 4, 5])
0 голосов
/ 16 августа 2010

Вы пишете поток, который может получать сообщения от других потоков, например, чтобы прекратить. Вы пишете код в потоке, чтобы отслеживать другие потоки, отправлять им сообщения о прекращении и ждать ответа. Поток найдет себя в списке, отправит себе сообщение для завершения и будет ждать завершения. Если это не было написано так, чтобы приоритезировать входящие сообщения над состоянием ожидания ...

...