1.多線程-了解多線程與高並發


並發與並行的區別:

並發:兩個任務或者多個任務執行,多個任務交替執行
並行:兩個任務或者多個任務一起同時執行
例子:

     一個CPU,去執行一個多線程任務。是不可能並行的,一個CPU只能執行一條命令,CPU會高速的切換線程任務去執行。這種情況下線程是並發的。
一個系統中擁有多個CPU,執行多線程任務,多個CPU會同時執行任務,這種情況是並行。並行也只可能出現在多核CPU中。
兩者雖然本質不同,但是造成的最終效果是一樣的。沒有太必要做詳細的區分。

臨界區:

     臨界區用來表示一個共享資源,可以被多個線程使用,但是每一次,只能有一個線程去使用。相等於廁所的坑。

阻塞非阻塞:

     假如有兩個線程,把他們當作兩個人,都拉肚子,只有一個廁所,兩人都必須要上這個廁所。

阻塞:

     一個人先進去了,另外一個人在等待,另外一個人必須要等第一個人出來,才能進去搞事情,這個就是阻塞行為。

非阻塞:

     強調沒有一個線程可以妨礙其他線程去執行任務。所有線程都會嘗試不斷前向執行。后面會有更詳細的描述。

死鎖,飢餓,活鎖

死鎖:

     一個單行道,有一個車,正在往前駕駛,然后有一個車從反方向駕駛過來,這兩個誰都不想退,那么這個狀態將會一直這樣維持下去。線程如果發生這種類似的行為,那么就可能會造成死鎖。

飢餓:

     某個線程或者多個線程因為某些原因無法獲得所需要的資源,比如有一個特大的餅,有很多人都想要吃,武力值高的肯定先吃,但是武力值高的人太多,導致那些武力值極低的人,會一直吃不到,這個就像等於線程中的優先級,優先級高的優先去做某事。跟死鎖相比,飢餓還是會在某一段時間解決的,比如武力值高的都吃餅吃飽了,就到武力值低的去吃了。

活鎖:

     過馬路的時候可能碰到這種情況,你往前走,有一個人騎着自行車往你這個方向駛來,他看到你了,你看到他了,你想讓他,他想讓你,你往左,他往右,你往右,他往左,兩個一直保持着禮讓的態度,就會一直這樣來回重復做這樣的事情。現實中還好說,人可以去交流,幾次過后就解決了,但是對於線程,如果沒有給線程賦予這種處理的思路,它就可能一直重復和另一個線程做這種“禮讓”的事情,導致沒有一個線程可以同時拿到所有資源去正常執行任務。

並發級別:

     由於臨界區的存在,我們必須控制多線程間的並發,根據控制並發的測率,我們可以把並發的級別進行分類,大致上可以分為:阻塞~無飢餓~無障礙~無鎖~無等待五種。

阻塞:

     java中的synchronized關鍵字,都會試圖去得到臨界區的鎖,如果得不到,線程就會被掛機等待,知道占有了資源為止。是一種悲觀策略,認為肯定會有線程去搶資源,一個線程搶到資源,其他的就會掛起等待執行完畢,再去試探。

無飢餓:

     公平鎖,不管優先級多高,講究的是先來后到,這樣所有的線程都有機會去執行。

無障礙:

     是一種樂觀策略,認為不會有線程去搶資源,無障礙的去執行,如果檢測到沖突,就回滾。

無鎖:

     保證有一個線程能在有限步內完成操作離開臨界區。

無等待:

     要求所有線程必須在有限步內完成操作。

線程的三個特性:

原子性:

     指的是一個操作不可中斷,哪怕多個線程同時操作一個變量,每個線程只改它要改的值,不管被其它線程修改成什么值。

可見性:

     並行多線程修改了某一個共享變量的值,其他線程並不一定能夠立即知道這個修改。

有序性:

     程序在執行的時候,程序的代碼執行順序和語句的順序是一致的,在Java內存模型中,允許編譯器和處理器對指令進行重排序,但是重排序過程不會影響到串行程序的執行,卻會影響到多線程並發執行的正確性。

指令重排:
 1/**
2 * @program: test
3 * @description: 
4 * @author: Mr.Yang
5 * @create: 2018-11-06 11:22
6 **/
7public class A {
8    int a=0;
9    boolean flag=false;
10    public void  write(){
11        a=1;
12        flag=true;
13    }
14    public void reader(){
15        if(flag){
16            int i =a+1;
17        }
18    }
19}

     假設線程A先執行writer方法,接着線程B執行reader()方法,如果發生指令重排,線程B在第11行代碼,不一定能看到a被賦值1了。

指令重排的原因:

     提高性能。可以共同執行任務,不需要等待第一個執行完成之后再去執行另一個任務。如果做成要任務執行完成再去執行另外一個,那么就和串行無太大區別了,性能也會嚴重受損。

一些指令是不能重排的:Happen-Before規則
程序順序原則:
  • 一個線程內保證代碼正常順序執行

  • volatile規則:volatile變量的寫,先發生與讀,保證了volatile的可見性

  • 鎖規則:解鎖必然發生在隨后的加鎖前

  • 傳遞性:A引用B,B引用C,那么C必然先在A前執行。

  • 線程的start()方法先於它的每一個動作

  • 線程的所有操作先於線程的完結

  • 線程的中斷先於被中斷線程的代碼

  • 對象的構造函數執行和結束先於finalize()方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM