并發程式設計帶來的問題
1.上下文切換問題
2.死鎖問題
上下文切換
多線程不一定快
1.線程有建立和上下文切換的開銷
如何減少上下文切換
減少上下文切換的方法有
無鎖程式設計
、
CAS算法
使用最小線程
使用協程
1.無鎖并發程式設計,多線程競争鎖時,會引起上下文切換,是以多線程處理資料時,可以用一些辦法來避免使用鎖,如将資料的ID按照hash算法取模分段,不同的線程處理不同段的資料
2.CAS算法。Java的Atomic包使用CAS算法來更新資料,而不需要加鎖,其實也加了鎖,隻不過加鎖于cpu上,系統開銷可忽略不計
3.使用最小線程。避免建立不需要的線程,比如任務很少,但是建立很多線程來處理,這樣會造成大量線程處于等待狀态
4.協程,在單線程裡實作多任務排程,并在單線程裡維持多個任務間的切換
死鎖
有如下代碼:
package com.fx.pattern.cor.handler;
public class DeadLockDemo {
private static String A = "A";
private static String B = "B";
public static void main(String[] args) {
new DeadLockDemo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A) {
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (B) {
System.out.println('1');
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B) {
synchronized (A) {
System.out.println('2');
}
}
}
});
t1.start();
t2.start();
}
這段代碼運作之後會引起死鎖,t1線程與t2線程互相等待對方釋放鎖。
待程式運作之後,我們采用如下方式來檢視jvm對程式的跟蹤棧資訊:
擷取目前程式程序id
1.ps aux | grep DeadLockDemo
程序id如下圖所示:
DeadLockTest PID.png
擷取目前程式産生的堆棧資訊
2.sudo -u root jstack -F 32125 > /Users/mark/Desktop/JAVA/dump
擷取到的堆棧資訊如下圖所示:
死鎖資訊.png
idea中堆棧資訊更加明确程式出現死鎖的代碼行數:
死鎖分析.png
避免死鎖的方法
1.避免一個線程同時擷取多個鎖
2.避免一個線程在鎖内同時占用多個資源,盡量保證每個鎖隻占用一個資源
3.嘗試使用定時鎖,使用lock.tryLock(timeout)來代替使用内部鎖機制。
4.對于資料庫鎖,加鎖和解鎖必須在一個資料庫連接配接裡,否則會出現解鎖失敗的情況。
資源限制的挑戰
什麼是資源限制
資源限制是指在并發程式設計時,程式的執行速度受限于計算機硬體資源或軟體資源
資源限制引發的問題
并發程式設計,将代碼執行速度加快的原則是将代碼中串行執行的部分變成并發執行,但将串行執行的代碼演變成并發執行,需要考慮到資源限制,資源受限的情況下,串行到并發的演變反而會使程式執行變得更慢,因為增加了上下文切換和資源排程的時間。
如何解決資源限制問題
硬體資源限制,考慮使用叢集并行執行程式,既然單機資源有限,那就讓程式在多機上運作。
軟體資源限制,考慮使用資源池将資源複用,比如使用連接配接池将資料庫和Socket連接配接複用,或者在調用對方webService接口擷取資料時,隻建立一個連接配接。
在資源限制情況下進行并發程式設計
1.根據不同的資源限制調整程式的并發度。涉及資料庫連接配接數的sql操作,如果sql語句執行非常快,但是線程數量比資料庫連接配接大很多,則某些線程會被阻塞,等待資料庫連接配接。
部落格搬家: 大坤的個人部落格 歡迎評論哦~