多線程學習(一)

最近,學習了下多線程,雖然工作中用不上,但還是多瞭解點爲好,技多不壓身。

什麼是線程:先了解什麼是進程,進程想必大家都知道,一個exe 打開後,在任務管理器裏面有這個文件的進程,一個進程肯定有多個服務協同工作組成,這個服務就是類似於線程的概念,

首先呢:多線程是爲了解決一類問題,而產生了多線程,例如:在某個場景下,一個業務操作多個數據庫,並且各個數據不相互影響,執行時間大致是2分鐘,這麼長時間,客戶肯定是等不及的,這時候,多線程就該商場表演了,由於每個服務相互不影響,所以多個線程執行的時間,肯定小於一個主線程執行業務的時間,稍後爲大家帶來feature模式,在此先稍微提下。

線程的優點:某些場景下執行時間快,大大提高了性能。

線程的缺點:操作不正確的情況下,會造成數據的不一致,引起髒讀。

1:說到線程,不得不提synchronized 現在企業級開發根本不用,因爲效率針對企業級開發來說效率太差,雖然sun對synchronized性能優化了一大堆。synchronized有兩種,一是同步方法,二是同步代碼塊,都能保證線程的安全。但是,性能不太高。

2:volatile  保證了數據的可見性,但保證不了數據的原子性,什麼意思呢:jdk5(jdk1.5)之後,sun公司針對多線程進行了優化,每個線程在共享區拿到數據之後,都會在自己的私有區域會建立一個類似於副本的概念,共享區數據發生變化,但是每個線程自己的私有區域有值得話,就不回去共享區拿數據,這樣會有了數據不一致的情況,所以,在這種情況下,volatile關鍵字就誕生啦,jetty框架裏面採用了大量的volatil關鍵字,所以性能肯定是非常好的。volatile 關鍵字加在變量上的意思就是:一旦共享區數據發生了變化,會強制要求每個線程更新自己的私有區域,跟共享區保持一致,這就是所謂的保證了數據的可見性,但是呢多個線程操作這個共享區的話,還是會引起髒讀。那到底什麼能保證數據的原子性呢,下面說

3:jdk下面有個包,裏面有個atomic類,不瞭解的同學可以百度百度,atomic關鍵字會保證數據的原子性,但是一個方法內,二次合二次以上的調用atomic的話,也會引起問題

4:wait notify 在某些情況下可以保證線程安全,之前阿里有個面試題:

public class MyStack {            private List<String> list = new ArrayList<String>();                    public synchronized void push(String value) {                synchronized (this) {                    list.add(value);                    notify();                }            }                    public synchronized String pop() throws InterruptedException {                synchronized (this) {                    if (list.size() <= 0) {                        wait();                    }                    return list.remove(list.size() - 1);                }            }        }
問題:  這段代碼大多數情況下運行正常,但是某些情況下會出問題。什麼時候會出現什麼問題?如何修正?

主要考察的是wait和notify的缺點:wait是立即釋放鎖,而notify會在方法執行完後釋放鎖,稍微解釋下上面的例子爲什麼會有問題

三個線程執行:a ,b ,c  a負責add 。b跟c 負責pop 。b先執行,發現沒元素,wait  然後a執行,添加了個元素,這時候方法執行完,釋放鎖,b跟c 相互搶,c先搶到,執行了remove 這時候,b在執行remove ,執行報錯。當然別把阿里面試題想的這麼簡單,下面會問,怎麼解決,解決的辦法很簡單,if判斷換成while循環就行。

多線程還有其他的方法,suspend和resume ,會引起的獨佔問題,stop方法太暴力,不建議使用,sleep, yield 和join的區別


----------------------------------------------------------------------------------------------------

二 線程的容器

線程的容器可以分爲:同步類容器和併發類容器。

    同步類容器就是synchronized的那種方式,併發類容器我知道的就是 currentMap 跟queue。currentMap裏面有個類似於段的概念,就是segment。currentMap裏面分爲16個段,每一個段都是一個同步的HashMap,這種方式提升了點併發類的性能,目前的話,沒什麼缺點,copyonwrite 應用場景就是讀多寫少的場景,因爲 遇到發生了寫的操作的話,線程先把容器的數據copy一份,不影響其他線程的讀,寫好了再把原來的引用指向新的引用,裏面實現是用reentrentLock實現,可以百度下鎖重入,這樣達到了同步。下面重點說書queue,queue分爲堵塞隊列跟非堵塞隊列,堵塞隊列就是帶有blocking的單詞的隊列,類似於 ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue,DelayQueue, priorityBlockingQueue ..每個queue都有各自的場景業務 ArrayBlockingQueue 有界隊列,LinkedBlockingQueue無界隊列,DelayQueue帶有延時時間的queue,priorityBlockingqueue,具有優先級的queue。這裏小小舉例下:

    一條馬路上,一個路口 , 早晨8點到10點是早高峯,10點到 下午4點正常,晚上12點後通暢,這三種情況好比三種任務,任務多的話,可以用ArrayBlockingQueue限制任務的數目,ListedListBlockingQueue 無界隊列,隨意加任務,沒有界限,晚上12點後,我想任務直接執行,不通過容器,那就用synchronousQueue。在這裏就不詳細講了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章