日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

java中多線程產(chǎn)生死鎖的原因以及解決意見(jiàn)

 instl 2019-03-27

1.  java中導(dǎo)致死鎖的原因

  多個(gè)線程同時(shí)被阻塞,它們中的一個(gè)或者全部都在等待某個(gè)資源被釋放,而該資源又被其他線程鎖定,從而導(dǎo)致每一個(gè)線程都得等其它線程釋放其鎖定的資源,造成了所有線程都無(wú)法正常結(jié)束。這是從網(wǎng)上其他文檔看到的死鎖產(chǎn)生的四個(gè)必要條件:

  • 1、互斥使用,即當(dāng)資源被一個(gè)線程使用(占有)時(shí),別的線程不能使用
  • 2、不可搶占,資源請(qǐng)求者不能強(qiáng)制從資源占有者手中奪取資源,資源只能由資源占有者主動(dòng)釋放。
  • 3、請(qǐng)求和保持,即當(dāng)資源請(qǐng)求者在請(qǐng)求其他的資源的同時(shí)保持對(duì)原有資源的占有。
  • 4、循環(huán)等待,即存在一個(gè)等待隊(duì)列:P1占有P2的資源,P2占有P3的資源,P3占有P1的資源。這樣就形成了一個(gè)等待環(huán)路。

當(dāng)上述四個(gè)條件都成立的時(shí)候,便形成死鎖。當(dāng)然,死鎖的情況下如果打破上述任何一個(gè)條件,便可讓死鎖消失。下面用java代碼來(lái)模擬一下死鎖的產(chǎn)生。

模擬兩個(gè)資源:

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

模擬線程1占用資源1并申請(qǐng)獲得資源2的鎖:

復(fù)制代碼
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");
    }
    
}
復(fù)制代碼

模擬線程2占用資源2并申請(qǐng)獲得資源1的鎖:

復(fù)制代碼
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");
    }
    
}
復(fù)制代碼

同時(shí)運(yùn)行倆個(gè)線程:

復(fù)制代碼
public class ThreadTest
{
    public static void main(String[] args)
    {
       new Thread(new Thread1()).start();
       new Thread(new Thread2()).start();
    }
}
復(fù)制代碼

最后輸出結(jié)果是:

Thread1 is running
Thread2 is running
Thread1 lock resource1
Thread2 lock resource2

并且程序一直無(wú)法結(jié)束。這就是由于線程1占用了資源1,此時(shí)線程2已經(jīng)占用資源2,。這個(gè)時(shí)候線程1想要使用資源2,線程2想要使用資源1,。兩個(gè)線程都無(wú)法讓步,導(dǎo)致程序死鎖。

2.  java避免死鎖的解決意見(jiàn)

由上面的例子可以看出當(dāng)線程在同步某個(gè)對(duì)象里,再去鎖定另外一個(gè)對(duì)象的話,就和容易發(fā)生死鎖的情況。最好是線程每次只鎖定一個(gè)對(duì)象并且在鎖定該對(duì)象的過(guò)程中不再去鎖定其他的對(duì)象,這樣就不會(huì)導(dǎo)致死鎖了。比如將以上的線程改成下面這種寫(xiě)法就可以避免死鎖:

復(fù)制代碼
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");
    }
復(fù)制代碼

但是有的時(shí)候業(yè)務(wù)需要同時(shí)去鎖定兩個(gè)對(duì)象,比如轉(zhuǎn)賬業(yè)務(wù):A給B轉(zhuǎn)賬,需要同時(shí)鎖定A、B兩個(gè)賬戶(hù)。如果A、B相互同時(shí)轉(zhuǎn)賬的話就會(huì)出現(xiàn)死鎖的情況。這時(shí)可以定義一個(gè)規(guī)則:鎖定賬戶(hù)先后的規(guī)則。根據(jù)賬戶(hù)的某一個(gè)屬性(比如id或者h(yuǎn)asCode),判斷鎖定的先后。即每一次轉(zhuǎn)賬業(yè)務(wù)都是先鎖定A再鎖定B(或者先鎖定B在鎖定A),這樣也不會(huì)導(dǎo)致死鎖的發(fā)生。比如按照上面的例子,需要同時(shí)鎖定兩個(gè)資源,可以根據(jù)資源的hashcode值大小來(lái)判斷先后鎖定順序。可以這樣改造線程:

復(fù)制代碼
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");
    }
    
}
復(fù)制代碼

總結(jié):死鎖常見(jiàn)于,線程在鎖定對(duì)象還沒(méi)釋放時(shí),又需要鎖定另一個(gè)對(duì)象,并且此時(shí)該對(duì)象可能被另一個(gè)線程鎖定。這種時(shí)候很容易導(dǎo)致死鎖。因此在開(kāi)發(fā)時(shí)需要慎重使用鎖,尤其是需要注意盡量不要在鎖里又加鎖。

 

注意:本文僅代表個(gè)人理解和看法喲!和本人所在公司和團(tuán)體無(wú)任何關(guān)系!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多