併發編程的開端
本章節四問,大家帶着問題來看。因爲我們叫程序員,不是碼農。
1.爲什麼出現併發編程,目的是什麼?
2.多線程的使用場景?
3.多線程有時比單線程慢
4.死鎖是什麼鬼?
解答:
1.併發編程
併發編程說白就是讓程序運行得更快,但並不是開啓多個線程就快。比如查詢10條數據庫記錄,你開10個線程來處理。是不是傻!如果通過多線程執行任務讓程序更快,我們要考慮很多。比如:cpu分給多個線程的時間片(上下文切換)、死鎖,還有軟硬件的資源問題。
2.多線程使用場景
單核也可以玩多線程,並不是多核的專利。CPU通過給每個線程分配時間片來實現,(jvm運行時數據區域裏面的程序計數器作用在此驗證)腦子發散了。迴歸正題!時間片就是給各個線程分配的執行時間,非常短。讓我們感覺多個線程同時執行,當前線程時間片到期時,在切換前保存當前線程的狀態,以便後面切換回來。這就是我們常說的上下文切換。
3.多線程有時比單線程慢
多線程不一定比單線程快,大家不妨自己寫累加操作從一萬次起測試,在百萬次時,執行效率還不如單線程高。這就是線程創建和上下文切消耗資源太大。
我們通過無鎖化編程、CAS、最少線程、協程
無鎖化編程:若數據id按照Hash算法取模分段,不同線程取不同數據。本質還是使用了鎖,涉及到機器架構等。
CAS:java的Atomic包使用CAS來更新數據,而不是加鎖。CAS是unsafe類裏面的,不過跟蹤到底層它本質還是使用了鎖。
最少線程:儘可能避免創建不需要的線程。綜合考慮
協程:在單線程實現多個任務切換執行。
通過jstack命令來輸出dump文件,然後分析優化。後續的jvm章節會說到。
4.死鎖
死鎖是指在一組進程中的各個線程均佔有不會釋放的資源,但因互相申請被其他線程所站用不會釋放的資源而處於的一種永久等待狀態
public class DeadLock {
public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static void main(String[] args){
Thread a = new Thread(new Lock1());
Thread b = new Thread(new Lock2());
a.start();
b.start();
}
}
class Lock1 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock1 running");
while(true){
synchronized(DeadLock.obj1){
System.out.println("Lock1 lock obj1");
Thread.sleep(3000);//獲取obj1後先等一會兒,讓Lock2有足夠的時間鎖住obj2
synchronized(DeadLock.obj2){
System.out.println("Lock1 lock obj2");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
class Lock2 implements Runnable{
@Override
public void run(){
try{
System.out.println("Lock2 running");
while(true){
synchronized(DeadLock.obj2){
System.out.println("Lock2 lock obj2");
Thread.sleep(3000);
synchronized(DeadLock.obj1){
System.out.println("Lock2 lock obj1");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
避免死鎖方法:
1) 避免一個線程同時獲取多個鎖
2)避免一個線程所內部同時佔用多個資源,儘量保證每個所只佔用一個資源
3)使用lock.tryLock來替換
資源限制怎麼解決:
硬件單機資源限制的話就多臺機器搞集羣,有錢就是買買買。
軟件限制考慮池化技術。複用!
下一篇: 併發機制原理