亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

java中常見的死鎖以及解決方法代碼

2024-07-14 08:43:40
字體:
來源:轉載
供稿:網友

在java中我們常常使用加鎖機制來確保線程安全,但是如果過度使用加鎖,則可能導致鎖順序死鎖。同樣,我們使用線程池和信號量來限制對資源的使用,但是這些被限制的行為可能會導致資源死鎖。java應用程序無法從死鎖中恢復過來,因此設計時一定要排序那些可能導致死鎖出現的條件。

1.一個最簡單的死鎖案例
當一個線程永遠地持有一個鎖,并且其他線程都嘗試獲得這個鎖時,那么它們將永遠被阻塞。在線程A持有鎖L并想獲得鎖M的同時,線程B持有鎖M并嘗試獲得鎖L,那么這兩個線程將永遠地等待下去。這種就是最簡答的死鎖形式(或者叫做"抱死")。

2.鎖順序死鎖

java,死鎖,解決方法,代碼

如圖:leftRight和rightLeft這兩個方法分別獲得left鎖和right鎖。如果一個線程調用了leftRight,而另一個線程調用了rightLeft,并且這兩個線程的操作是交互執行,那么它們就會發生死鎖。

死鎖的原因就是兩個線程試圖以不同的順序來獲得相同的鎖。所以,如果所有的線程以固定的順序來獲得鎖,那么在程序中就不會出現鎖順序死鎖的問題。

2.1.動態的鎖順序死鎖

我以一個經典的轉賬案例來進行說明,我們知道轉賬就是將資金從一個賬戶轉入另一個賬戶。在開始轉賬之前,首先需要獲得這兩個賬戶對象得鎖,以確保通過原子方式來更新兩個賬戶中的余額,同時又不破壞一些不變形條件,例如 賬戶的余額不能為負數。

所以寫出的代碼如下:

//動態的鎖的順序死鎖public class DynamicOrderDeadlock {		public static void transferMoney(Account fromAccount,Account toAccount,int amount,int from_index,int to_index) throws Exception {		System.out.println("賬戶 "+ from_index+"~和賬戶~"+to_index+" ~請求鎖");				synchronized (fromAccount) {			System.out.println("	賬戶 >>>"+from_index+" <<<獲得鎖");			synchronized (toAccount) {				System.out.println("		  賬戶   "+from_index+" & "+to_index+"都獲得鎖");				if (fromAccount.compareTo(amount) < 0) {					throw new Exception();				}else {					fromAccount.debit(amount);					toAccount.credit(amount);				}			}		}	} 	static class Account {		private int balance = 100000;//這里假設每個人賬戶里面初始化的錢		private final int accNo;		private static final AtomicInteger sequence = new AtomicInteger();				public Account() {			accNo = sequence.incrementAndGet();		}				void debit(int m) throws InterruptedException {			Thread.sleep(5);//模擬操作時間			balance = balance + m;		}				void credit(int m) throws InterruptedException {			Thread.sleep(5);//模擬操作時間			balance = balance - m;		} 				int getBalance() {			return balance;		}				int getAccNo() {			return accNo;		}				public int compareTo(int money) {			if (balance > money) {				return 1;			}else if (balance < money) {				return -1;			}else {				return 0;			}		}	}}
public class DemonstrateDeadLock {	private static final int NUM_THREADS = 5;	private static final int NUM_ACCOUNTS = 5;	private static final int NUM_ITERATIONS = 100000;	public static void main(String[] args) {		final Random rnd = new Random();		final Account[] accounts = new Account[NUM_ACCOUNTS];				for(int i = 0;i < accounts.length;i++) {			accounts[i] = new Account();		}						class TransferThread extends Thread{			@Override			public void run() {				for(int i = 0;i < NUM_ITERATIONS;i++) { 					int fromAcct = rnd.nextInt(NUM_ACCOUNTS);					int toAcct =rnd.nextInt(NUM_ACCOUNTS);					int amount = rnd.nextInt(100);					try {						DynamicOrderDeadlock.transferMoney(accounts[fromAcct],accounts[toAcct], amount,fromAcct,toAcct);							//InduceLockOrder.transferMoney(accounts[fromAcct],accounts[toAcct], amount);						 //InduceLockOrder2.transferMoney(accounts[fromAcct],accounts[toAcct], amount);					}catch (Exception e) {						System.out.println("發生異常-------"+e);					}				}			}		}		 		for(int i = 0;i < NUM_THREADS;i++) {			new TransferThread().start();		}	}}

打印結果如下:
注意:這里的結果是我把已經執行完的給刪除后,只剩下導致死鎖的請求.

java,死鎖,解決方法,代碼

 

 

 

 

//通過鎖順序來避免死鎖public class InduceLockOrder {	private static final Object tieLock = new Object();	public static void transferMoney(final Account fromAcct, final Account toAcct, final int amount)			throws Exception {		class Helper {			public void transfer() throws Exception {				if (fromAcct.compareTo(amount) < 0) {					throw new Exception();				} else {					fromAcct.debit(amount);					toAcct.credit(amount);				}			}		}		int fromHash = System.identityHashCode(fromAcct);		int toHash = System.identityHashCode(toAcct);		if (fromHash < toHash) {			synchronized (fromAcct) {				synchronized (toAcct) {					new Helper().transfer();				}			}		} else if (fromHash > toHash) {			synchronized (toAcct) {				synchronized (fromAcct) {					new Helper().transfer();				}			}		} else {			synchronized (tieLock) {				synchronized (fromAcct) {					synchronized (toAcct) {						new Helper().transfer();					}				}			}		}	}		static class Account {		private int balance = 100000;		public Account() {		}				void debit(int m) throws InterruptedException {			Thread.sleep(5);			balance = balance + m;		}				void credit(int m) throws InterruptedException {			Thread.sleep(5);			balance = balance - m;		} 				int getBalance() {			return balance;		}		public int compareTo(int money) {			if (balance > money) {				return 1;			}else if (balance < money) {				return -1;			}else {				return 0;			}		}			}}

經過我測試,此方案可行,不會造成死鎖。

方案二

在Account中包含一個唯一的,不可變的,值。比如說賬號等。通過對這個值對對象進行排序。
具體代碼如下

public class InduceLockOrder2 {	public static void transferMoney(final Account fromAcct, final Account toAcct, final int amount)			throws Exception {		class Helper {			public void transfer() throws Exception {				if (fromAcct.compareTo(amount) < 0) {					throw new Exception();				} else {					fromAcct.debit(amount);					toAcct.credit(amount);				}			}		}		int fromHash = fromAcct.getAccNo();		int toHash = toAcct.getAccNo();		if (fromHash < toHash) {			synchronized (fromAcct) {				synchronized (toAcct) {					new Helper().transfer();				}			}		} else if (fromHash > toHash) {			synchronized (toAcct) {				synchronized (fromAcct) {					new Helper().transfer();				}			}		} 	}		static class Account {		private int balance = 100000;		private final int accNo;		private static final AtomicInteger sequence = new AtomicInteger();				public Account() {			accNo = sequence.incrementAndGet();		}				void debit(int m) throws InterruptedException {			Thread.sleep(6);			balance = balance + m;		}				void credit(int m) throws InterruptedException {			Thread.sleep(6);			balance = balance - m;		} 				int getBalance() {			return balance;		}				int getAccNo() {			return accNo;		}		public int compareTo(int money) {			if (balance > money) {				return 1;			}else if (balance < money) {				return -1;			}else {				return 0;			}		}			}}

經過測試此方案也可行。

2.2在協作對象之間發生的死鎖
如果在持有鎖時調用某外部的方法,那么將出現活躍性問題。在這個外部方法中可能會獲取其他的鎖(這個可能產生死鎖),或阻塞時間過長,導致其他線程無法及時獲得當前持有的鎖。

場景如下:Taxi代表出租車對象,包含當前位置和目的地。Dispatcher代表車隊。當一個線程收到GPS更新事件時掉用setLocation,那么它首先更新出租車的位置,然后判斷它是否到達目的地。如果已經到達,它會通知Dispatcher:它需要一個新的目的地。因為setLocation和notifyAvailable都是同步方法,因此掉用setLocation線程首先獲取taxi的鎖,然后在獲取Dispatcher的鎖。同樣,掉用getImage的線程首先獲取Dispatcher的鎖,再獲取每一個taxi的鎖,這兩個線程按照不同的順序來獲取鎖,因此可能導致死鎖。

能造成死鎖的代碼如下:

//會發生死鎖public class CooperatingDeadLock {	// 坐標類	class Point {		private final int x;		private final int y;		public Point(int x, int y) {			this.x = x;			this.y = y;		}		public int getX() {			return x;		}		public int getY() {			return y;		}	}	// 出租車類	class Taxi {		private Point location, destination;		private final Dispatcher dispatcher;				public Taxi(Dispatcher dispatcher) {			this.dispatcher = dispatcher;		}				public synchronized Point getLocation() {			return location;		}						public synchronized void setLocation(Point location) {			this.location = location;			if (location.equals(destination)) {				dispatcher.notifyAvailable(this);			}		}						public synchronized Point getDestination() {			return destination;		}				public synchronized void setDestination(Point destination) {			this.destination = destination;		}	}	class Dispatcher {		private final Set<Taxi> taxis;		private final Set<Taxi> availableTaxis;		public Dispatcher() {			taxis = new HashSet<>();			availableTaxis = new HashSet<>();		}				public synchronized void notifyAvailable(Taxi taxi) {			availableTaxis.add(taxi);		}		public synchronized Image getImage() {			Image image = new Image();			for(Taxi t:taxis) {				image.drawMarker(t.getLocation());			}			return image;		}	}		class Image{		public void drawMarker(Point p) {					}	}}

解決方案:使用開放掉用。
如果再調用某個方法時不需要持有鎖,那么這種調用就被稱為開放掉用。這種調用能有效的避免死鎖,并且易于分析線程安全。

修改后的代碼如下:

//此方案不會造成死鎖public class CooperatingNoDeadlock {	// 坐標類		class Point {			private final int x;			private final int y;			public Point(int x, int y) {				this.x = x;				this.y = y;			}			public int getX() {				return x;			}			public int getY() {				return y;			}		}		// 出租車類		class Taxi {			private Point location, destination;			private final Dispatcher dispatcher;						public Taxi(Dispatcher dispatcher) {				this.dispatcher = dispatcher;			}						public synchronized Point getLocation() {				return location;			}									public void setLocation(Point location) {				boolean reachedDestination;				synchronized (this) {					this.location = location;					reachedDestination = location.equals(destination);				}				if (reachedDestination) {					dispatcher.notifyAvailable(this);				}			}									public synchronized Point getDestination() {				return destination;			}						public synchronized void setDestination(Point destination) {				this.destination = destination;			}		}		class Dispatcher {			private final Set<Taxi> taxis;			private final Set<Taxi> availableTaxis;			public Dispatcher() {				taxis = new HashSet<>();				availableTaxis = new HashSet<>();			}						public synchronized void notifyAvailable(Taxi taxi) {				availableTaxis.add(taxi);			}			public Image getImage() {				Set<Taxi> copy;				synchronized (this) {					copy = new HashSet<>(taxis);				}								Image image = new Image();				for(Taxi t:copy) {					image.drawMarker(t.getLocation());				}				return image;			}								}				class Image{			public void drawMarker(Point p) {							}		}}

總結:活躍性故障是一個非常嚴重的問題,因為當出現活躍性故障時,除了終止應用程序之外沒有其他任何機制可以幫助從這種故障中恢復過來。最常見的活躍性故障就是鎖順序死鎖。在設計時應該避免產生順序死鎖:確保線程在獲取多個鎖時采用一直的順序。最好的解決方案是在程序中始終使用開放掉用。這將大大減小需要同時持有多個鎖的地方,也更容易發現這些地方。

以上所述是小編給大家介紹的java中常見的死鎖以及解決方法詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91国语精品自产拍在线观看性色| 国产视频欧美视频| 91免费精品视频| 亚洲综合色av| 精品国产1区2区| 亚洲精品一区久久久久久| 5252色成人免费视频| 青草热久免费精品视频| 成人黄色免费看| 亚洲奶大毛多的老太婆| 97香蕉超级碰碰久久免费的优势| 日韩黄色高清视频| 亚洲高清福利视频| 91欧美精品午夜性色福利在线| 青青草原一区二区| 在线视频欧美性高潮| 国产精品都在这里| 92福利视频午夜1000合集在线观看| 成人激情在线观看| 亚洲欧美制服综合另类| 中国日韩欧美久久久久久久久| 亚洲成人网av| 中文字幕久久久| 91免费版网站入口| 欧美视频一二三| 亚洲18私人小影院| 一区二区三区四区在线观看视频| 亚洲free性xxxx护士白浆| 国产午夜精品视频免费不卡69堂| 亚洲国产成人久久| 亚洲人成电影网站色www| 亚洲女人被黑人巨大进入| 91牛牛免费视频| 久久福利网址导航| 这里只有视频精品| 色偷偷亚洲男人天堂| 日韩在线激情视频| 国产中文字幕日韩| 欧美巨乳美女视频| 国产午夜精品美女视频明星a级| 国产亚洲精品美女久久久| 久久久亚洲精品视频| 欧美国产视频一区二区| 欧美黑人极品猛少妇色xxxxx| 欧美激情视频网站| 揄拍成人国产精品视频| 国产精品久久久av| 欧美激情三级免费| 最新亚洲国产精品| 福利视频一区二区| 136fldh精品导航福利| 日韩在线一区二区三区免费视频| 91久久久久久久久久久| 自拍偷拍免费精品| 欧美午夜片在线免费观看| 97色在线视频观看| 国产精品网站大全| 懂色av中文一区二区三区天美| 北条麻妃一区二区三区中文字幕| 国产区精品在线观看| 国产成人在线播放| 亚洲精品www| 久久成人这里只有精品| 日韩欧美在线观看视频| 亚洲视频视频在线| 国产91精品久久久久久久| 欧美激情精品久久久久久| 亚洲精品色婷婷福利天堂| 久久夜色撩人精品| 久久久久久这里只有精品| 亚洲一区二区在线| 久久精视频免费在线久久完整在线看| www亚洲精品| 久久久精品一区二区三区| 国产一区二区三区在线播放免费观看| 日本欧美中文字幕| 国产日韩精品综合网站| 亚洲国产成人精品久久久国产成人一区| 亚洲国产美女精品久久久久∴| 亚洲午夜精品视频| 97高清免费视频| 欧美美女操人视频| 97精品在线观看| 亚洲国产天堂久久综合| 亚洲女人天堂视频| 国语自产精品视频在免费| 国产精品色婷婷视频| 国产日韩中文在线| 韩国视频理论视频久久| 国产综合久久久久| 国产女人精品视频| 国产性猛交xxxx免费看久久| 欧美成人免费观看| 欧美激情日韩图片| 九九九久久久久久| 国产精品视频网址| 久久久久久国产精品三级玉女聊斋| 在线精品高清中文字幕| 性色av一区二区咪爱| 日本精品一区二区三区在线| 久久成人精品一区二区三区| 欧美电影在线观看网站| 亚洲欧美日韩天堂| 国产精品久久久久久av福利| 国产欧美一区二区三区久久人妖| 中文欧美在线视频| 欧美精品999| 热re99久久精品国产66热| 91高清免费视频| 一区二区三区亚洲| 成人久久久久爱| 亚洲人成亚洲人成在线观看| 热久久视久久精品18亚洲精品| 免费91麻豆精品国产自产在线观看| 久久久噜久噜久久综合| 亚洲国产99精品国自产| 亚洲午夜色婷婷在线| 欧美精品激情在线观看| 国产精品第8页| 萌白酱国产一区二区| 欧美日韩中文字幕在线视频| 欧美激情免费在线| 国产成人亚洲综合91精品| 欧美放荡办公室videos4k| 夜色77av精品影院| 日韩精品在线第一页| 久久久久久久久亚洲| 亚洲国产成人久久综合一区| 欧美中文字幕在线观看| 欧美性猛交xxxx黑人| 国产亚洲欧美日韩精品| 亚洲成人国产精品| 久久精品国亚洲| 欧美一区视频在线| 日韩精品在线观看一区| 欧美日韩在线视频一区| 少妇精69xxtheporn| 国产精品久久久久免费a∨| 国产精品欧美日韩| 日韩av电影在线网| 欧美在线影院在线视频| 欧美亚洲日本网站| 精品一区精品二区| 久久97精品久久久久久久不卡| 国产va免费精品高清在线观看| 欧美成人激情视频| 亚洲精品国精品久久99热| 欧美激情精品久久久久久| 国产精品青草久久久久福利99| 亚洲精品黄网在线观看| 韩日欧美一区二区| 日韩高清电影好看的电视剧电影| 超碰日本道色综合久久综合| 亚洲黄色免费三级| 亚洲福利在线视频| 亚洲成人精品久久久| 国产欧美va欧美va香蕉在线| 国产裸体写真av一区二区| 欧美孕妇孕交黑巨大网站| 欧美日韩中国免费专区在线看| 久久91精品国产| 久久久噜噜噜久久久| 日韩久久免费电影| 欧美一乱一性一交一视频|