java之J.U.C係列文章--概括與基礎
J.U.C是java係列一塊看似簡單,水很深的區域,但是不論是深入java還是分布式的一些東西,這都算是基礎,雖然以前亂七八糟寫過一些多線程的文章,不過都比較亂了一點,最近有打算逐步深入來寫多篇文章來說說我對這些東西的小理解。
1、首先線程分為內核線程、用戶線程;在Linux下java的線程其實是在java私有棧上有一個用戶線程,和OS級別有一個輕量級的進程來實現。
2、在操作java多線程的時候必然會遇到鎖的問題,在鎖的問題中,線程會首先進入一個所謂的Entry Set的集合中,然後嚐試去征用鎖,征用到鎖的就是他的owner,沒有征用到,調用wait(),那麼就進入Wait Set的區域中,使用完後,鎖被釋放,調用notfiy或notifyAll歡迎Wait Set區域的內容重新嚐試,和Entry Set裏麵的信息一起征用;調用sleep是沒有鎖的;synchronized是係統級別的鎖;notify是喚醒一個Wait Set區域的等待線程,而notifyAll是喚醒所有相關的線程,join是當前線程會等待對應的幾個線程執行完再向下走;Daemon設置為true設置為後台線程,指:主線程執行完後,後台線程自動完成,否則不會;yield是當前讓出一個CPU的時間,給其他線程來做,但是讓多久,誰也不知道,要知道讓多久,sleep知道。
3、blocked狀態的線程一般是掛住的線程,由於鎖機製的原因導致,或一些網絡原因導致,並且此時interrupt是無法斷開的,鎖機製的問題在後續的文章中會介紹很多機製來避免,但是網絡機製的在java中請用socket的超時soTimeout來設置超時,否則無法斷開(包括連接數據庫等)soTimeout意義在於發生一次read操作的時候,連接超時時間,也就是等結果的時候一直沒等到,而不是總的連接超時;
4、interrupt隻會對wait和time_wait狀態的線程有效,如果程序是處於循環運行狀態,外部發起一個interrupt命令要求停止這個線程,此時程序默認是不會被停止的,所以你在看某些框架的時候,裏麵會在循環體內部有一個操作是:
Thread.currentThread().isInterrupted()
就是判定當前線程時候被中斷,從這裏你可以看出中斷隻是在線程上打了一個tag(true|false),此時你發現被中斷就應該break跳出循環;注意還有一個方法是:interrupted();這個方法不僅僅會設置方法是否被中斷,而且還會設置線程是未中斷的狀態,也就是將interrupt的狀態重新會設置為false,不過當前會返回false,可以在任意一個main方法中寫一下代碼測試:
Thread.currentThread().interrupt(); System.out.println(Thread.currentThread().interrupted()); System.out.println(Thread.currentThread().interrupted()); //Thread.currentThread().interrupt(); System.out.println(Thread.currentThread().isInterrupted()); System.out.println(Thread.currentThread().isInterrupted());
然後將注釋掉的代碼打開再看看結果;源碼部分很簡單:
public boolean isInterrupted() { return isInterrupted(false); } public static boolean interrupted() { return currentThread().isInterrupted(true); }
上一篇文章說過一些關於CPU Cache Line的一些問題,其實可以看出,如果你想要自己在java的內存中設置緩存的話,建議這些緩存是基本不被修改的,最好是final的;如果是變化的保證可見性的情況下需要選擇volatile、保證原子性優先選擇Atomic*,不到萬不得已,不自己玩鎖,尤其是在靜態方法或Class上去做鎖;關於可見性的描述,後麵的文章中還會更加深入的闡述下。
5、java 現在提供了很多java.util.concurrent包來替代原來的很多集合類,但並不代表可以解決所有問題,也不代表原來的集合類沒用,更加更加不代表不需要了解各種集合類的特征和使用場景;在後麵的文章中我們會介紹這些內容的細節,總之如果你發現你所要訪問的內容存在多線程的訪問,並且他們是可能被修改的,那麼就存在並發,並發就存在諸多的問題需要處理;
6、有人認為,並發時我不確保數據的正確性的情況下或者報個錯也可以接受,不使用非並發包(HashMap這類)也覺得可以,NO,在並發的情況下有些時候不僅僅是報錯的問題,有些時候可能會引起並發時Key重複死循環情況。
7、ABA問題是我們比較痛苦的問題,即使使用很多並發的機製來解決也未必是真實的,所以對於ABA問題,java為我們提供了版本控製的方法,後續文章也逐步說明。
8、ThreadLocal這把雙刃劍,能爽死你,也能玩死你;ThreadLoad在傳遞參數的時候,是非常有效的,加參數也很方便,他是與當前線程綁定的,不過查問題痛苦了,尤其是這些東西被封裝到三方包裏麵的時候,因為WEB模型的線程是不會被釋放的,所以ThreadLocal內部的參數也不會釋放,在什麼地方被修改一個不知道,其次容易引起內存泄露。
9、JVM也為你提供了各種各樣的線程池,他們能為你解決什麼,和普通線程的區別,線程池的處理模型和策略;通過線程池如何完成一個調度器的功能;通過線程池完成很多的現實模型而不需要你自己去寫算法去解決一些複雜惡心的線程交互問題;在這裏還有一個Future、FutureTask是咋回事;這個我們在後麵說
10、鎖機製的到底是啥玩意,現在的java如何玩鎖,怎麼玩清楚鎖;synchronized、Lock(ReentrantLock、ReadWriteLock)如何選擇,等待隊列分組;啥時候死鎖,除了交叉死鎖還有什麼死鎖?tryLock咋玩的?如何提升一些性能?
11、Queue、List、Map並發容器的介紹和使用;CountDownLatch、Semaphone、CyclicBarrier、Exchanger使用(AbstractQueuedSynchronizer)工具篇;後續專門介紹。
12、Atomic係列之Atomic<基本的變量>、Atomic<基本變量>FiledUpdater、Atomic<基本變量>Array,以及AtomicReference(引用)、AtomicStampedReference(帶版本號的引用)、AtomicMarkableReference(可以進行計數);後續專門說明;
本文除了前麵的簡單介紹外,後續部分就是一個大概介紹,由於篇幅所限,隻能逐步完善後麵的內容。
最後更新:2017-04-02 16:48:12