併發編程的基礎,應該是離不開多線程,本問先簡單介紹一下多線程的基礎。
一、多線程實現方式
總所周知,有四種創建線程的方法,分別是:
1.繼承Thread類 重寫run方法
2.實現Runnable接口,重寫run方法
3.匿名內部類方式
4.線程池
總的來說,都是圍繞Thread類和Runnable接口來進行操作的,工作中使用最多的應該是線程池(之後介紹)。
二、線程的概念以及線程和進程的關聯
進程是計算機中的程序關於某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位。線程是程序執行的最小單位。舉個栗子:高鐵站就是一個進程,高鐵站負責人(系統)會對整個高鐵站進行資源分配和調度,線程則是每一條鐵路。
三、線程的分類
分爲用戶線程和守護線程,用戶線程:就是用戶自定義創建的線程,主線程停止,用戶線程不會停止;守護線程:守護線程當進程不存在或主線程停止,守護線程也會被停止。
守護線程的用法也很簡單,使用setDaemon(true)方法設置爲守護線程,需要在start()之前設置好,否則會設置守護線程失敗,而當做用戶線程使用。
四、線程的生命週期
新建狀態、就緒狀態、運行狀態、阻塞狀態及死亡狀態。
就緒、運行、阻塞三種狀態可以來回切換,如:就緒狀態轉爲運行狀態,運行轉阻塞,阻塞可以再轉回運行狀態。只要不走到死亡,它就一直存活。
五、java內存模型
簡稱JMM,決定一個線程對共享變量寫入時,能對另一個線程可見。一個共享資源存放在主內存中,每個線程會保存一份該共享資源的副本,當某一線程對副本進行操作的時候,將更改的資源刷新到主內存,然後通知其他線程刷新本地內存中的副本,這樣就保證了可見性。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(main memory)中,每個線程都有一個私有的本地內存(local memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存,寫緩衝區,寄存器以及其他的硬件和編譯器優化。
三大特性。
1、原子性
一個操作時不可中斷的。即使是在多個線程一起執行的時候,一個操作一單開始,就不會被其他線程干擾。
2、可見性
當一個線程修改了某一個共享變量的值,其他線程是否能夠立即知道這個修改。在使用全局共享變量一般都會使用volatile關鍵字保證可見性,及時將資源刷到主內存中,而且會禁止重排序。
3、有序性
對於一個線程來說,執行代碼都是按照從先往後依次執行的。但是,在併發時,程序的執行可能就會出現亂序。產生亂序的原因是因爲程序在執行時,可能會進行指令重排。
所謂重排序,就是會對沒有依賴關係的指令進行重排序,以提高效率。類似流水線的工作原理,比如有兩條指令,指令A和指令B,指令A=a+b,指令B=c+d,這兩條指令沒有任何的依賴關係,那麼編譯器和處理器可能會對操作做重排序。如果指令A=a+b,指令B=A+c,那麼這兩條指令就有依賴關係,就不會進行重排序。