-5

在业务流程的某个地方,我的线程被锁定。所以在那之后,一切都将处于等待状态。如果它是这样的,那么我如何在不暂停应用程序的情况下继续进行。这意味着我不想终止应用程序。其实是面试题。

4

2 回答 2

1

首先,也是最重要的,强烈建议好好阅读一下死锁维基百科条目。特别是关于死锁处理的部分。

如果这是一个面试问题,面试官可能更感兴趣的是候选人对死锁如何发生以及如何防止和/或解决死锁的知识。

这是一个使用通过在一组对象上同步来创建 java 死锁的基本示例

private static void synchronizedBlockDeadlock()
{
    final Object resource1 = new Object();
    final Object resource2 = new Object();

    Runnable thread1 = new Runnable()
    {

        public void run()
        {
            synchronized (resource1)
            {
                final int sleepTimeMs = 1000;
                try
                {
                    Thread.sleep(sleepTimeMs);
                }
                catch (InterruptedException e) {}

                synchronized (resource2)
                {
                    System.out.println("In thread1");
                }
            }
        }
    };

    Runnable thread2 = new Runnable()
    {

        public void run()
        {
            synchronized (resource2)
            {
                final int sleepTimeMs = 1000;
                try
                {
                    Thread.sleep(sleepTimeMs);
                }
                catch (InterruptedException e) {}

                synchronized (resource1)
                {
                    System.out.println("In thread2");
                }
            }
        }
    };

    new Thread(thread1).start();
    new Thread(thread2).start();
}

首先,两个线程(有效)同时运行。线程 1 将获取资源 1 的锁,然后休眠一会儿,使线程 2 将获取资源 2 的锁。当然,这是基于线程 2 能够在线程 1 中的睡眠调用返回之前启动的假设。现在,线程 2 尝试获取由线程 1 持有的资源 1 上的锁,因此它无限期地阻塞。线程 1 唤醒并尝试获取资源 2 上的锁,该锁由线程 2 持有。两个线程都被另一个线程阻塞,因此所有线程都死锁了。

现在,可以重新编写此代码以使用显式锁来防止死锁(与通过“同步”关键字对资源对象实例进行隐式锁相反)。

请看下面的代码:

private static void explicitLockDeadlock()
{
    final Lock lock1 = new ReentrantLock();
    final Lock lock2 = new ReentrantLock();

    Runnable thread1 = new Runnable()
    {

        public void run()
        {
            try
            {
                lock1.tryLock(5, TimeUnit.SECONDS);
                System.out.println("Thread-1: Lock 1 acquired");

                final int sleepTimeMs = 1000;
                Thread.sleep(sleepTimeMs);

                lock2.tryLock(5, TimeUnit.SECONDS);
                System.out.println("Thread-1: Lock 2 acquired");
            }
            catch (InterruptedException e) {}
            finally
            {
                lock1.unlock();
            }

            System.out.println("In thread1");
        }
    };

    Runnable thread2 = new Runnable()
    {

        public void run()
        {
            try
            {
                lock2.tryLock(5, TimeUnit.SECONDS);
                System.out.println("Thread-2: Lock 2 acquired");

                lock1.tryLock(5, TimeUnit.SECONDS);
                System.out.println("Thread-2: Lock 1 acquired");
            }
            catch (InterruptedException e) {}
            finally
            {
                lock2.unlock();
            }

            System.out.println("In thread2");
        }
    };

    new Thread(thread1).start();
    new Thread(thread2).start();
}

这种方法是抢占可能死锁的线程或打破 4 Coffman 条件的“不抢占”条件的实例。实际上,等待的“tryLock”调用会在指定时间段后过期,从而防止应用程序无限期挂起。

于 2013-06-15T20:23:54.997 回答
0

使用jps或任务管理器获取进程 ID,然后jstack -F <pid>获取所有线程的堆栈跟踪和锁定信息(包括有关检测到的死锁的一些提示)。

于 2013-06-15T20:28:08.803 回答