多線程詳解

MYSQL基礎詳解:https://www.cnblogs.com/itchang/p/5784863.html
事物隔離性詳解:https://www.cnblogs.com/fjdingsd/p/5273008.html
阿里JAVA開發手冊:http://kangroo.gitee.io/ajcg/#/naming-style
Java關鍵字final、static使用總結:http://blog.51cto.com/lavasoft/18771html

--------------------------------------------------------------------------------------------------
多線程
進程:進程是線程的集合,正在運行的應用程序。
線程:線程是一條執行路徑,一個獨立的執行單元。
多線程做用:調高程序效率。
建立線程的方法:
    1:集成Thread類
    2:實現Runnable接口
    3:匿名內部類
    4:callable
    5:線程池
同步:代碼從上往下執行,又稱:單線程
異步:每一個線程之間互不影響,又稱:多線程
守護線程:和主線程,GC線程一塊兒銷燬
非守護線程:主線程銷燬了,仍是會繼續執行的
進程中包括了,主線程,GC線程,用戶線程(用戶本身建立的線程,非守護線程)
多線程運行狀態:新建狀態  -  就緒狀態  -  運行狀態  -  阻塞狀態  -  死亡狀態
多線程運行狀態流程圖:http://img.blog.csdn.net/20161017181631639?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
線程安全問題:當多個線程共享同一個全局、靜態變量,作寫操做時,可能會受到其餘線程的干擾,致使數據衝突的問題呢
解決線程安全問題:
    1:同步synchroized -- 自動釋放 
    2:鎖(locak)        -- 手動釋放
爲何使用同步或者鎖能解決線程安全問題?
    多個線程共享同一個全局、靜態變量時,只讓一個線程的代碼執行,代碼執行完畢後釋放鎖,在讓其餘線程執行。
這裏須要注意一下,
同步和線程同步不是一個概念
程序中的同步是單線程的,代碼從上往下執行
線程同步是保證線程安全
同步synchroized執行方法
1:同步代碼塊  -- 使用的是對象鎖
    synchroized(鎖){}
2:同步函數        -- 使用的是this鎖
    public synchroized void add(){}
3: 靜態同步函數        -- 使用的是當前字節碼文件鎖(類名.class)
    public static synchroized void add(){}java

注意:在多線程的同步中使用的不是同一把鎖,那麼線程仍是不安全的git

同步synchroized必須有的條件
    1:必需要有兩個線程以上,須要發生同步
    2:多個線程想同步,必須用同一把鎖
    3:保證只有一個線程進行執行算法

同步synchroized原理
    1:有一個線程已經拿到鎖了,其餘線程會一直等待,直到線程釋放了鎖,其餘線程將會搶這把鎖,搶到鎖的線程將會執行代碼。
同步synchroized缺點:效率低
死鎖:同步中嵌套同步,沒法釋放,一直等待,變成死鎖。數據庫

多線程三大特性
原子性:在操做中要麼都執行,要麼都不執行,保證數據一致
可見性:java內存模型,一個線程修改了共享變量值,其餘線程能過當即得知這個修改後的值
有序性:程序執行的順序按照代碼的前後順序執行數組

java內存模型(JMM):一個線程對共享變量寫入是,能對別的線程可見
流程圖:https://sfault-image.b0.upaiyun.com/140/667/1406676357-594a0dc7e13e8_articlex
java內存模式
主內存:主要存放共享全局變量
私有本地內存(工做內存):本地線程私有變量緩存

看流程圖就知道爲何數據會不可見了。
線程1從主內存中獲取到共享變量(A)到工做內存1中,而後在修改共享變量(A)的值,在修改期間,線程2從主內存中獲取到共享變量(A)到工做內存2中(這裏須要注意的是,線程1還沒修改值,線程2獲取到的是舊的值),線程1修改完後將共享變量(A)傳遞給主內存中,這就發生了可見行的問題。
加上volatile就能夠解決可見性問題:private static volatile int A;安全

volatile的做用:保證線程之間可見性,不保存原子性
AtomicInteger的做用:保證原子性
多線程通信方式:https://static.oschina.net/uploads/space/2018/0125/120221_Ronq_3578766.png多線程


wait():讓當前線程從運行狀態變成休眠狀態,釋放鎖的資源
notify(): 讓單錢線程從休眠的狀態變成運行狀態
注意,在同步中才能使用wait()、notify()
join():等待主線程執行完畢
Lock鎖
Lock鎖的寫法
    Lock lock  = new ReentrantLock();
    lock.lock();
    try{
    //可能會出現線程安全的操做
    }finally{
    //必定在finally中釋放鎖
    //也不能把獲取鎖在try中進行,由於有可能在獲取鎖的時候拋出異常
      lock.ublock();
    }併發

Lock鎖與synchronized同步鎖的區別
lock手動鎖
synchronized同步自動鎖 

Condition用法
 Condition的功能相似於在傳統的線程技術中的,Object.wait()和Object.notify()的功能。


線程安全的類
Vector和ArrayList區別
    實現原理都是經過數據實現,查詢速度快,增長,修改,刪除速度慢
    區別:線程安全問題
    Vector是安全(上鎖的集合),ArrayList線程不安全
    ArrayList效率高
    
Hashtable和HasMap集合
    Hashtable線程是安全
    HasMap線程是不安全
    鏈表+數組 put Hascode取模獲得下標位置 一致性取模算法
    證實:Hashtable是線程安全?查看源碼的put方法

JDK併發包
前言:
    在JDK1.5以後,發明一種新併發包
    JDK1.5以後,產生了不少java併發包
    Hashtable線程是安全,效率很是低,鎖的資源競爭。
    多線程共享同一個hashtable 加鎖、影響效率、每次只能有個線程去操做hashtable

併發安全類
ConcurrenHashMap -- 併發包
    分段鎖 默認16段
    將一個總體(集合)拆分紅多個小的Hashtable,默認分紅16段
    這樣就能夠有效的減小鎖的資源競爭
    
CountDownLatch --計數用的

CyclicBarrier --計數用的

併發隊列 --生產者消費者概念
在併發隊列中分有界、無界
有界、無界的區別
    爲防止理解不深,先引用一個問題
        數組和集合的區別
            數組是有長度限制的、集合是沒有長度限制的
    同等
    有界是有限制的,無界是無限制的

阻塞隊列、非阻塞隊列 --這裏要注意是阻塞'隊列'
區別:
    生產者寫入滿的時候,就會進入到阻塞。
    當隊列爲空的時候,消費者也會進入阻塞。
    
隊列遵循的規則
    先進先出
    後進後出

ConcurrentLinkedDeque和BlockingQueue的區別:
    BlockingQueue能夠阻塞,有界。
    ConcurrentLinkedDeque不可阻塞,無界。


多線程
什麼是線程池
    Java中的線程池是運用場景最多的併發框架,幾乎全部須要異步或併發執行任務的程序
    均可以使用線程池。在開發過程當中,合理地使用線程池可以帶來3個好處。
    第一:下降資源消耗。經過重複利用已建立的線程下降線程建立和銷燬形成的消耗。
    第二:提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行。
    第三:提升線程的可管理性。線程是稀缺資源,若是無限制地建立,不只會消耗系統資源,
    還會下降系統的穩定性,使用線程池能夠進行統一分配、調優和監控。可是,要作到合理利用
    線程池,必須對其實現原理了如指掌。

線程池做用
    線程池是爲忽然大量爆發的線程設計的,經過有限的幾個固定線程爲大量的操做服務,減小了建立和銷燬線程所需的時間,從而提升效率。
    若是一個線程的時間很是長,就不必用線程池了(不是不能做長時間操做,而是不宜。),何況咱們還不能控制線程池中線程的開始、掛起、和停止。

在線程池中 ThreadPoolExecutor 是核心類

線程池四種建立方式
Executor封裝了四種線程池類型
Java經過Executors(jdk1.5併發包)提供四種線程池,分別爲:
    1,newCachedThreadPool建立一個可緩存線程池,若是線程池長度超過處理須要,可靈活回收空閒線程,若無可回收,則新建線程。
    2,newFixedThreadPool 建立一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
    3,newScheduledThreadPool 建立一個定長線程池,支持定時及週期性任務執行。
    4,newSingleThreadExecutor 建立一個單線程化的線程池,它只會用惟一的工做線程來執行任務,保證全部任務按照指定順序(FIFO, LIFO, 優先級)執行。


java中線程池 核心使用的構造函數 採用ThreadPoolExecutor
ThreadPoolExecutor構造函數參數
    corePoolSize: 核心池的大小
    maximumPoolSize: 線程池最大線程數
    keepAliveTime: 終止時間
    unit: 超時秒數

線程池原理
線程池原理剖析
提交一個任務到線程池中,線程池的處理流程以下:
一、判斷線程池裏的核心線程是否都在執行任務,若是不是(核心線程空閒或者還有核心線程沒有被建立)則建立一個新的工做線程來執行任務。若是核心線程都在執行任務,則進入下個流程。
二、線程池判斷工做隊列是否已滿,若是工做隊列沒有滿,則將新提交的任務存儲在這個工做隊列裏。若是工做隊列滿了,則進入下個流程。
三、判斷線程池裏的線程是否都處於工做狀態,若是沒有,則建立一個新的工做線程來執行任務。若是已經滿了,則交給飽和策略來處理這個任務。

線程池 合理配置 --
    CPU密集 : 線程數和CPU數相同
        CPU使用頻繁就使用
    IO密集:2*CPU核數
        操做數據庫,IO須要等待,線程都須要等待,阻塞
        
CPU密集和IO密集的區別
    IO密集常常會有阻塞,休眠,CPU密集會頻繁的調用


java鎖機制
    悲觀鎖
    樂觀鎖
    分段鎖
    重入鎖
    讀寫鎖
    CAS無鎖
    自旋鎖
    排它鎖

    
案例:
    買水果案例
        小明買了10塊水果,給了老闆錢。然而小紅不知道小明給了錢,小紅又給了老闆10塊。(數據重複)
    在「多數據源」的狀況下(2個或者2個以上的JDBC鏈接)就要使用鎖
    
什麼是悲觀鎖?
    默認加排它鎖
    每次在拿數據的時候,都會上鎖。
    悲觀鎖:悲觀鎖悲觀的認爲每一次操做都會形成更新丟失問題,在每次查詢時加上排他鎖。
    每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿    這個數據就會block直到它拿到鎖。傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比    行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。

    使用方法:
        SQL語句後面添加 for update
    例子:
        select * from order for update
    原理:
        只容許有一個鏈接進行操做,當一個線程進入後會鎖住,別的線程要等待鎖釋放才能使用
    缺點:
        效率低 --由於只能保證一個鏈接進行操做
    
什麼是樂觀鎖?
    版本控制
    樂觀鎖:樂觀鎖會樂觀的認爲每次查詢都不會形成更新丟失,利用版本字段控制
    原理:
        首先數據庫中有個版本號(version),2個數據源同時操做SQL語句,第一個操做的時候version是0,而後會把version+1(版本號+1),那麼第二個操做的時候查詢version=0的數據是沒有的,查不到的,最後判斷影響行數就能夠了,假如影響行數>0就能夠進行操做

    悲觀鎖和樂觀鎖的區別
        若是查詢量小,可使用悲觀鎖
        使用版本控制操做,使用樂觀鎖


什麼是重入鎖?
    重入鎖(ReentrantLock 和synchronized) 與 非重入鎖(死鎖) 遞歸使用同步


什麼是讀寫鎖?
    兩個線程同時讀一個資源沒有任何問題,因此應該容許多個線程能在同時讀取共享資源。可是若是有一個線程想去寫這些共享資源,就不該該再有其它線程對該資源進行讀或寫(譯者注:也就是說:讀-讀能共存,讀-寫不能共存,寫-寫不能共存)
    

什麼是CAS無鎖?
    原子類底層如何實現保證線程安全,CAS無所機制效率比有所機制搞。
    CAS無所機制其實和樂觀鎖概念相似
    
    CAS體系中有三個參數
        它包含三個參數CAS(V,E,N): V表示要更新的變量,E表示預期值,N表示新值。僅當V值等於E值時,纔會將V的值設爲N,若是V值和E值不一樣,則說明已經有其餘線程作了更新,則當前線程什麼都不作。最後,CAS返回當前V的真實值。
    實現過程:
        當V=E表示沒有任何線程操做,那麼N值改成V值,返回N
        但V!=E表示有線程操做過,那麼N值改成E值,返回V
    例子:
        AtomicInteger就是CAS無鎖機制實現的

什麼是自旋鎖?     內部不停的進行循環

相關文章
相關標籤/搜索