執行緒知識點(筆記)
執行緒
synchronized和Lock鎖的區別?
1.存在層次上,synchronized是Java的關鍵字,在jvm層面上;而Lock是一個類
2.鎖的釋放上,synchronized是 1、以獲取鎖的執行緒執行完同步代碼,釋放鎖 2、執行緒執行發生例外,jvm會讓執行緒釋放鎖;
而Lock是在finally中必須釋放鎖(lock.unlock()),不然容易造成執行緒死鎖
3.鎖的獲取上,synchronized是假設A執行緒獲得鎖,B執行緒等待,如果A執行緒阻塞,B執行緒會一直等待;
而Lock是嘗試獲得鎖,執行緒可以不用一直等待
4.鎖狀態上,synchronized是無法判斷;而Lock是可以判斷
5.鎖型別上,synchronized是可重入 不可中斷 非公平;
而Lock是可重入 可判斷 可公平(兩者皆可) - 默認使用ReentrantLock無參構造方法,則創建非公平鎖
6.性能上,synchronized是盡量同步少量代碼;
而Lock是可以同步大量代碼
7.目前上synchronized已經逐步優化,并且是JVM"親生的"
鎖
可重入鎖:在執行物件中所有同步方法不用再次獲得鎖
可中斷鎖:在等待獲取鎖程序中可中斷
公平鎖: 按等待獲取鎖的執行緒的等待時間進行獲取,等待時間長的具有優先獲取鎖權利
讀寫鎖:對資源讀取和寫入的時候拆分為2部分處理,讀的時候可以多執行緒一起讀,寫的時候必須同步地寫
wait和sleep的區別?
共同點: 他們都是在多執行緒的環境下,都可以在程式的呼叫處阻塞指定的毫秒數,并回傳,
不同點:
1.Thread.sleep(long)可以不在synchronized的塊下呼叫,而且使用Thread.sleep()不會丟失當前執行緒對任何物件的同步鎖(monitor);
2.0object.wait(long)必須在synchronized的塊下來使用,呼叫了之后失去對object的monitor(同步鎖), 這樣做的好處是它不影響其它的執行緒對object進行操作,(不用synchronized會拋例外IllegalMonitorStateException)
3.sleep()是個靜態方法 wait()非靜態方法,屬于Object
execute()和submit()區別
1.兩者皆是執行執行緒任務
2.submit() ExecutorService中的; execute() Executor中的
ExecutorService extends Executor
3.void execute(Runnable command);
Future submit(Callable task);
Future<?> submit(Runnable task);
execute方法只能執行Runnable的任務,并且沒有回傳值;
submit方法既可以執行Runnable任務回傳null,也能執行Callable任務有回傳值;
4.submit方便Exception處理,可以通過捕獲Future中的get()拋出的例外;
Callable的call()任務里可以拋出例外,而又希望外面的呼叫者能夠感知這些exception并做出及時的處理,
例如有很多更新各種資料的任務task,希望如果其中一個task失敗,其它的task就不需要執行了,
那就需要catch Future.get拋出的例外ExecutionException ,然后終止其它task的執行,
執行緒池
執行緒池作業原理
合理利用執行緒池能夠帶來三個好處
- 降低資源消耗,減少了創建和銷毀執行緒的次數,每個作業執行緒都可以被重復利用,可執行多個任務,
- 提高回應速度,當任務到達時,任務可以不需要的等到執行緒創建就能立即執行,
- 提高執行緒的可管理性,可以根據系統的承受能力,調整執行緒池中作業線執行緒的數目,防止因為消耗過多的記憶體,而把服務器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最后死機),
執行緒池的作用
執行緒池作用就是限制系統中執行執行緒的數量,
? 根據系統的環境情況,可以自動或手動設定執行緒數量,達到運行的最佳效果;
少了浪費了系統資源,多了造成系統擁擠效率不高,
用執行緒池控制執行緒數量,其他執行緒排隊等候,
? 一個任務執行完畢,再從佇列的中取最前面的任務開始執行,若佇列中沒有等待任務,執行緒池的這一資源處于等待,當一個新任務需要運行時,如果執行緒池中有等待的作業執行緒,就可以開始運行了;否則進入等待佇列,
為什么要用執行緒池
1.減少了創建和銷毀執行緒的次數,每個作業執行緒都可以被重復利用,可執行多個任務,
2.可以根據系統的承受能力,調整執行緒池中作業線執行緒的數目,防止因為消耗過多的記憶體,而把服務器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最后死機),
Java里面執行緒池的頂級介面是Executors,嚴格意義上講Executors并不是一個執行緒池,而只是一個執行執行緒的工具,真正的執行緒池介面ExecutorService,
比較重要的幾個類
ExecutorService 真正的執行緒池介面,
ScheduledExecutorService 能和Timer/TimerTask類似,解決那些需要任務重復執行的問題,
ThreadPoolExecutor ExecutorService的默認實作,
ScheduledThreadPoolExecutor 繼承ThreadPoolExecutor的ScheduledExecutorService介面實作,周期性任務調度的類實作,
要配置一個執行緒池是比較復雜的,尤其是對于執行緒池的原理不是很清楚的情況下,很有可能配置的執行緒池不是較優的,因此在Executors類里面提供了一些靜態工廠,生成一些常用的執行緒池,
- newSingleThreadExecutor
創建一個單執行緒的執行緒池,這個執行緒池只有一個執行緒在作業,也就是相當于單執行緒串行執行所有任務,如果這個唯一的執行緒因為例外結束,那么會有一個新的執行緒來替代它,此執行緒池保證所有任務的執行順序按照任務的提交順序執行, - newFixedThreadPool
創建固定大小的執行緒池,
每次提交一個任務就創建一個執行緒,直到執行緒達到執行緒池的最大大小,
執行緒池的大小一旦達到最大值就會保持不變,如果某個執行緒因為執行例外而結束,
那么執行緒池會補充一個新執行緒, - newCachedThreadPool
創建一個可快取的執行緒池,
如果執行緒池的大小超過了處理任務所需要的執行緒,
那么會回收部分空閑(60秒不執行任務)的執行緒,當任務數增加時,
此執行緒池又可以智能的添加新執行緒來處理任務,此執行緒池不會對執行緒池大小做限制,
執行緒池大小完全依賴于作業系統(或者說JVM)能夠創建的最大執行緒大小, - newScheduledThreadPool
創建一個大小無限的執行緒池,此執行緒池支持定時以及周期性執行任務的需求,
死鎖
什么是死鎖
? 在多執行緒程式中,使用了多把鎖,造成執行緒之間相互等待.程式不往下走了,
產生死鎖的條件
1.有多把鎖
2.有多個執行緒
3.有同步代碼塊嵌套
執行緒三大特性
可見性
解決執行緒間變數的不可見性的方案有兩種常見方式
? 1.加鎖
? 解決原因:會清空作業記憶體,讀取主記憶體中最新值到作業記憶體中來,
? 2.對共享的變數進行volatile關鍵字修飾
? 解決原因:一旦一個執行緒中的變數,添加了volatile修飾符,其它執行緒可以立即讀取到最新值
volatile與synchronized的區別
1).volatile只能修飾實體變數和類變數,而synchronized可以修飾方法,以及代碼塊,
2).volatile保證資料的可見性,但是不保證原子性(即:多執行緒進行寫操作,不保證執行緒安全);而synchronized是一種排他(互斥)的機制,實作執行緒安全,
3).從性能上說,volatile更好點,僅僅是對實作執行緒間變數的可見性上,
原子性
? 概述:所謂的原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了執行并且不會受到任何因素的干擾而中斷,要么所有的操作都不執行,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/325462.html
標籤:其他
