1.併發編程的挑戰之死鎖
死鎖是兩個或更多線程阻塞着等待其它處於死鎖狀態的線程所持有的鎖。死鎖通常發生在多個線程同時但以不同的順序請求同一組鎖的時候。
例如,如果線程1鎖住了A,然後嘗試對B進行加鎖,同時線程2已經鎖住了B,接着嘗試對A進行加鎖,這時死鎖就發生了。線程1永遠得不到B,線程2也永遠得不到A,並且它們永遠也不會知道發生了這樣的事情。爲了得到彼此的對象(A和B),它們將永遠阻塞下去。這種情況就是一個死鎖。
舉個例子:A和B打架,兩人都想抓住對方的頭髮,於是我們可以依此編寫如下的程序:
/**
* 死鎖
*/
public class DeadLockDemo {
private static final Object HAIR_A = new Object();
private static final Object HAIR_B = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (HAIR_A) {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (HAIR_B) {
System.out.println("A成功抓住B的頭髮");
}
}
}).start();
new Thread(() -> {
synchronized (HAIR_B) {
synchronized (HAIR_A) {
System.out.println("B成功抓住A的頭髮");
}
}
}).start();
}
}
這個時候由於A和B都想要獲取對方的鎖,而雙方都緊握不放,導致誰也抓不到誰,最終一直僵持下去,造成死鎖的發生,這個時候我們可以用監視器查相應的死鎖狀況:
2.併發編程的挑戰之線程安全
線程安全就是多線程訪問時,採用了加鎖機制,當一個線程訪問該類的某個數據時,進行保護,其他線程不能進行訪問直到該線程讀取完,其他線程纔可使用。不會出現數據不一致或者數據污染。
線程不安全就是不提供數據訪問保護,有可能出現多個線程先後更改數據造成所得到的數據是髒數據
下面我們來看一個例子,採取10個線程對num進行++的操作,此時會發現每次得到的結果都不一樣;這個就是線程不安全造成的結果:
package xianchengxuexi;
import java.util.concurrent.CountDownLatch;
/**
* 線程不安全操作
*/
public class UnSafeThread {
private static int num = 0;
private static CountDownLatch countDownLatch =new CountDownLatch(10);
/**
* 每次調用對num進行++的操作
*
*/
public static void increment(){
num++;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
for (int j = 0; j <100 ; j++) {
increment();
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//在每個線程只想完後調用cutdown
countDownLatch.countDown();
}).start();
}
while (true){
if(countDownLatch.getCount()==0){
break;
}
}
System.out.println(num);
}
}
此結果產生的原因用簡圖描述如下,就是在線程1睡眠的過程中,第二個線程進行了操作,但是拿到的結果仍然是未更新的值,也就是髒數據,這個進行操作就沒有同步,造成線程不安全:
3.併發編程的挑戰之資源挑戰
- 硬件資源
- 服務器: 1m 本機:2m
- 帶寬的上傳/下載速度、硬盤讀寫速度和CPU的處理速度。
- 軟件資源
- 數據庫連接 500個連接 1000個線程查詢 並不會因此而加快 socket