b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Java多线程死锁的原因及解决方法

电脑杂谈  发布时间:2020-04-12 12:12:44  来源:网络整理

线程死锁 解决_多线程如何避免死锁_避免线程死锁

1. Java死锁的原因

同时阻塞多个线程,其中一个或所有线程都在等待释放资源,并且该资源被其他线程锁定,这导致每个线程都在等待其他线程释放其锁定的资源. 结果,所有线程无法正常结束. 这些是从Internet上其他文档中看到的僵局的四个必要条件:

当以上四个条件都成立时,就会形成死锁. 当然,在死锁的情况下,如果以上任何条件被破坏,则死锁可能会消失. 以下使用Java代码模拟死锁的产生.

模拟两种资源:

多线程如何避免死锁_线程死锁 解决_避免线程死锁

public class ThreadResource
{
    public static Object resource1 = new Object();
    
    public static Object resource2 = new Object();
}

模拟线程1占用资源1并申请对资源2的锁定.

public class Thread1 implements Runnable
{
    
    @Override
    public void run()
    {
        try
        {
            System.out.println("Thread1 is running");
            synchronized (ThreadResource.resource1)
            {
                System.out.println("Thread1 lock resource1");
                Thread.sleep(2000);//休眠2s等待线程2锁定资源2
                synchronized (ThreadResource.resource2)
                {
                    System.out.println("Thread1 lock resource2");
                }
                System.out.println("Thread1 release resource2");
            }
            System.out.println("Thread1 release resource1");
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread1 is stop");
    }
    
}

模拟线程2占用资源2并申请对资源1的锁定:

避免线程死锁_多线程如何避免死锁_线程死锁 解决

public class Thread2 implements Runnable
{
    
    @Override
    public void run()
    {
        try
        {
            System.out.println("Thread2 is running");
            synchronized (ThreadResource.resource2)
            {
                System.out.println("Thread2 lock resource2");
                Thread.sleep(2000);//休眠2s等待线程1锁定资源1
                synchronized (ThreadResource.resource1)
                {
                    System.out.println("Thread2 lock resource1");
                }
                System.out.println("Thread2 release resource1");
            }
            System.out.println("Thread2 release resource2");
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread2 is stop");
    }
    
}

同时运行两个线程:

public class ThreadTest
{
    public static void main(String[] args)
    {
       new Thread(new Thread1()).start();
       new Thread(new Thread2()).start();
    }
}

最终输出是:

避免线程死锁_线程死锁 解决_多线程如何避免死锁

线程1正在运行

Thread2正在运行

线程1锁定resource1

线程2锁定resource2

线程死锁 解决_避免线程死锁_多线程如何避免死锁

该程序从未结束. 这是因为线程1占用了资源1,而线程2已经占用了资源2. 这时,线程1想要使用资源2多线程如何避免死锁,线程2想要使用资源1. 这两个线程都不能屈服,从而导致程序死锁.

2. 避免死锁的Java解决方案

从上面的示例可以看出,当线程正在同步一个对象,然后另一个对象被锁定时,很可能导致死锁. 最好是线程一次只锁定一个对象多线程如何避免死锁,而在锁定对象的过程中不再锁定其他对象,这样就不会导致死锁. 例如,将上述线程更改为以下编写方式可以避免死锁:

public void run()
    {
        try
        {
            System.out.println("Thread1 is running");
            synchronized (ThreadResource.resource1)
            {
                System.out.println("Thread1 lock resource1");
                Thread.sleep(2000);//休眠2s等待线程2锁定资源2
            }
            System.out.println("Thread1 release resource1");
            synchronized (ThreadResource.resource2)
            {
                System.out.println("Thread1 lock resource2");
            }
            System.out.println("Thread1 release resource2");
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread1 is stop");
    }

但是有时业务需要同时锁定两个对象,例如转账业务: A转到B,必须同时锁定A和B帐户. 如果A和B同时进行汇款,则会发生死锁. 此时,可以定义一个规则: 依次锁定帐户的规则. 根据帐户的某个属性(例如id或hasCode),确定锁定的顺序. 也就是说,每个传输事务都将锁定A,然后锁定B(或在锁定A之前锁定B),这不会导致死锁. 例如,根据上述示例,需要同时锁定两个资源,并且可以根据资源的哈希码值确定锁定顺序. 可以这样修改线程:

public class Thread3 implements Runnable
{
    
    @Override
    public void run()
    {
        try
        {
            System.out.println("Thread is running");
            if ( ThreadResource.resource1.hashCode() > ThreadResource.resource2.hashCode() )
            {
                //先锁定resource1
                synchronized (ThreadResource.resource1)
                {
                    System.out.println("Thread lock resource1");
                    Thread.sleep(2000);
                    synchronized (ThreadResource.resource2)
                    {
                        System.out.println("Thread lock resource2");
                    }
                    System.out.println("Thread release resource2");
                }
                System.out.println("Thread release resource1");
            }
            else
            {
                //先锁定resource2
                synchronized (ThreadResource.resource2)
                {
                    System.out.println("Thread lock resource2");
                    Thread.sleep(2000);
                    synchronized (ThreadResource.resource1)
                    {
                        System.out.println("Thread lock resource1");
                    }
                    System.out.println("Thread release resource1");
                }
                System.out.println("Thread release resource2");
            }
        }
        catch (Exception e)
        {
            System.out.println(e.getMessage());
        }
        System.out.println("Thread1 is stop");
    }
    
}

摘要: 当线程在释放锁定的对象之前需要锁定另一个对象时,死锁很常见,并且此时该对象可能已被另一个线程锁定. 这一次很容易造成死锁. 因此,有必要在开发过程中谨慎使用锁,尤其是要避免在锁中尽可能多地添加锁.

注意: 本文仅代表个人的理解和见解!与我的公司和集团无关!


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-172923-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      热点图片
      拼命载入中...