面試題:
寫出一個死鎖的實例。
Java發生死鎖的根本原因是:
死鎖是因爲多線程訪問共享資源,由於訪問的順序不當所造成的,在申請鎖時發生了交叉閉環申請。即線程在獲得了鎖A並且沒有釋放的情況下去申請鎖B,這時,另一個線程已經獲得了鎖B,在釋放鎖B之前又要先獲得鎖A,因此閉環發生,陷入死鎖循環。
實例1:
在MyLock類中定義兩個不同的靜態鎖對象。
package com.deadLock;
class MyLock{
static Object locka = new Object(); //注意此處必須時static,
static Object lockb = new Object(); //不僅能類名訪問,也是讓不同線程訪問共享數據
}
class Lock implements Runnable{
private boolean flag;
public Lock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag){
while(true){
deadLockab();
}
}else{
while(true){
deadLockba();
}
}
}
private void deadLockab() {
String name = Thread.currentThread().getName();
synchronized (MyLock.locka){
System.out.println(name+"...lock on "+MyLock.locka);
synchronized (MyLock.lockb){
System.out.println(name+"...lock on "+MyLock.lockb);
}
}
}
private void deadLockba() {
String name = Thread.currentThread().getName();
synchronized (MyLock.lockb){
System.out.println(name+"...lock on "+MyLock.lockb);
synchronized (MyLock.locka){
System.out.println(name+"...lock on "+MyLock.locka);
}
}
}
}
public class DeadLockDemo2 {
public static void main(String[] args) {
Thread t1 = new Thread(new Lock(true));
Thread t2 = new Thread(new Lock(false));
t1.start();
t2.start();
}
}
運行結果(形成死鎖):
實例2(無法形成死鎖):
在實現Runnable類中定義兩個不同的鎖,注意兩個線程任務不同,所以這兩個鎖並不是默認靜態鎖。
package com.deadLock;
class Lock implements Runnable{
private boolean flag;
private Object obj1 = new Object();
private Object obj2 = new Object();
public Lock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag){
while(true){
deadLockab();
}
}else{
while(true){
deadLockba();
}
}
}
private void deadLockab() {
String name = Thread.currentThread().getName();
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
}
}
}
private void deadLockba() {
String name = Thread.currentThread().getName();
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
}
}
}
}
public class DeadLockDemo2 {
public static void main(String[] args) {
Thread t1 = new Thread(new Lock(true));
Thread t2 = new Thread(new Lock(false));
t1.start();
t2.start();
}
}
運行結果:
實例3(實例2改進,形成死鎖):
在實現Runnable類中定義兩個不同的鎖,並且兩個線程任務不同,兩個鎖必須手動聲明爲靜態鎖。
package com.notdeadlock;
class Lock implements Runnable{
private boolean flag;
private static Object obj1 = new Object();
private static Object obj2 = new Object();
public Lock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag){
while(true){
deadLockab();
}
}else{
while(true){
deadLockba();
}
}
}
private void deadLockab() {
String name = Thread.currentThread().getName();
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
}
}
}
private void deadLockba() {
String name = Thread.currentThread().getName();
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
}
}
}
}
public class NotDeadLock{
public static void main(String[] args) {
Thread t1 = new Thread(new Lock(true));
Thread t2 = new Thread(new Lock(false));
t1.start();
t2.start();
}
}
運行結果:
實例4(形成死鎖(2個線程)):
package com.deadlock3;
class Lock implements Runnable{
private Object obj1; //注意此處不能爲final/static
private Object obj2;
//如果final就不能在下面構造方法中重新賦值;如果static所有線程共享鎖,線程t1,t2都在使用obj2這把鎖,無法形成死鎖。
public Lock(Object obj1, Object obj2) {
this.obj1 = obj1;
this.obj2 = obj2;
}
@Override
public void run() {
while(true){
deadLock();
}
}
private void deadLock() {
String name = Thread.currentThread().getName();
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
}
}
}
}
public class DeadLockDemo3 {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
Thread t1 = new Thread(new Lock(obj1, obj2));
Thread t2 = new Thread(new Lock(obj2, obj1));
t1.start();
t2.start();
}
}
運行結果:
實例5(形成死鎖(3個線程)):
package com.deadlock3;
class Lock implements Runnable{
private Object obj1; //注意此處不能爲final/static
private Object obj2;
//如果final就不能在下面構造方法中重新賦值;如果static所有線程共享鎖,最後只有兩把鎖,無法鎖住所有線程。
public Lock(Object obj1, Object obj2) {
this.obj1 = obj1;
this.obj2 = obj2;
}
@Override
public void run() {
while(true){
deadLock();
}
}
private void deadLock() {
String name = Thread.currentThread().getName();
synchronized (obj1){
System.out.println(name+"...lock on "+obj1);
synchronized (obj2){
System.out.println(name+"...lock on "+obj2);
}
}
}
}
public class DeadLockDemo3 {
public static void main(String[] args) {
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = new Object();
Thread t1 = new Thread(new Lock(obj1, obj2));
Thread t2 = new Thread(new Lock(obj2, obj3));
Thread t3 = new Thread(new Lock(obj3, obj1));
t1.start();
t2.start();
t3.start();
}
}
運行結果:
總結:
推薦使用實例4這種方法形成死鎖,代碼簡單,理解起來也很方便,如果有什麼問題,歡迎一起探討。