java多線程中死鎖情況的一個示例
來源:程序員人生 發布時間:2015-01-14 08:48:21 閱讀次數:3223次
下面是死鎖情況的1個示例代碼
package com.qust.demo.money;
class A {
public synchronized void foo(B b) {
System.out.println(Thread.currentThread().getName() + " 進入A的foo");
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 試圖調用B的last");
b.last();
}
public synchronized void last() {
System.out.println("A的last()");
}
}
class B {
public synchronized void bar(A a) {
System.out.println(Thread.currentThread().getName() + " 進入B的bar");
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 試圖調用A的last");
a.last();
}
public synchronized void last() {
System.out.println("B的last()");
}
}
public class DeadLock implements Runnable {
A a = new A();
B b = new B();
public void init() {
Thread.currentThread().setName("主線程");
System.out.println("進入主線程");
a.foo(b);
}
public void run() {
Thread.currentThread().setName("副線程");
System.out.println("進入副線程");
b.bar(a);
}
public static void main(String[] args) {
DeadLock dl = new DeadLock();
new Thread(dl).start();
dl.init();
}
}
下面是運行結果
進入主線程
進入副線程
主線程 進入A的foo
副線程 進入B的bar
副線程 試圖調用A的last
主線程 試圖調用B的last
我們看到,正常情況下,最后還應當打印出“A的last()”和"B的last()",但是由于線程死鎖的緣由,所以程序1直在等待履行,沒能正常的履行下去。
在上面的代碼里面,為何會出現死鎖這類情況呢?我們來簡單分析1下。
首先雖然副線程的start()是在主線程的init()之前,但是由于多線程開啟也需要1段時間,所以我們可以看到,是主線程的init()方法履行在前,然后在init()里面調用了a.foo()。A類和B類中的方法都是同步方法,因此,A的對象和B的對象都是同步鎖。在進入A的foo()之前,線程會對A加鎖,然后線程睡眠200ms,這時候候副線程調用B的bar(),一樣的會對B加鎖,然后睡眠200ms。這時候候,主線程喚醒,試圖調用B的bar方法,由于是同步方法,所以需要對B加鎖,但是這時候候B已被副線程鎖住了,所以主線程就1直處于阻塞狀態。當副線程喚醒的時候,試圖調用A的同步方法,一樣需要對A加鎖,但是這時候候主線程持有A的鎖,并處于阻塞狀態,所以副線程也不能向下履行,大家都在等著對方釋放鎖,因此出現了我們上面說的死鎖的情況。
如果我們把A和B的last()的synchronized去掉,那末程序在調用last()之前就不需要對對象進行加鎖,也就不會出現死鎖的情況。
由于在工作中還沒有遇到這類情況,所以只能拿這個實例程序講授了。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈