java基礎(執行緒)
技術標籤:Java
1.執行緒的啟動
繼承自Thread
A a1 = new A(1000);
a1.start();
2.實現介面Runnable
A a1 = new A(1000);類A實現介面Runnable
Thread t1 = new Thread(a1);
t1.start();
- Callable介面的實現
特點:
在方法體中可丟擲異常
方法體有返回值,用於線上程執行完畢後,返回執行的結果
3.2 實現步驟
定義類B 實現介面Callable,並實現其方法call
定義物件FutureTask rs = new Future(b);
new Thread(rs,“執行緒名”).start();
4.執行緒池–重點
4.1 背景
對於一些單個任務處理時間短但任務數量大的應用,建立和銷燬執行緒所消耗的資源比執行緒執行所佔用資源更多,這種
情況都可通過執行緒池解決。
4.2 工作原理
當請求過來時,執行緒已經被執行緒池提前建立好了,可直接申請使用。當請求結束時,執行緒不再銷燬而是重新放回池子
中再複用。當併發請求過多時,可讓請求等待在佇列中,甚至拒絕新請求從而避免請求太多導致系統崩潰。
4.3 各種執行緒池特點: - newFixedThreadPool(n):
池子中最多n個執行緒,當有請求過來時,就建立執行緒,最多三個,第四個及以後的請求
入佇列中等待,直到前面執行緒結束,才會從佇列中獲取任務並啟動任務
缺點:
1.當沒有任務時,不會銷燬之前建立的執行緒
2.當有大量請求都入佇列時,容易導致OOM(out of memery,記憶體溢位)
- newCachedThreadPool:
最大執行緒無限制,無任務時,執行緒存活的最大時間為1分鐘 - newSingleThreadExecutor:
只有一個執行緒提供服務,過多的任務入佇列 - ThreadPoolExecutor
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,4,3,TimeUnit.SECONDS,new
ArrayBlockingQueue<>(3),new ThreadPoolExecutor. DiscardOldestPolicy());
4.4 池子的方法
submit(o):向池子申請執行緒服務
shutdown():會把當前正在執行的執行緒和佇列中的執行緒執行完畢再關閉池子
shutdownnow():會把正在執行的執行緒執行完畢就關閉,不再執行佇列中的任務
5.執行緒生命週期
2.常用方法
Thread.sleep(n):休眠n毫秒
Thread.currentThread():獲取當前執行緒物件
start():啟動執行緒
setName()和getName()設定或獲取執行緒名
yield():讓執行緒進入runnable,也就是準備就緒狀態
join():會讓當前執行緒處於阻塞,直到插入執行緒執行完畢才解除阻塞
setPriority(int n):優先順序設定,範圍在1~10,預設是5,優先順序高的得到的時間片多於優先順序低的.
CountDownLatch:減法器
await:當某個執行緒呼叫該方法時,會讓該執行緒阻塞,直到計數器為0才解除阻塞
countDown():某執行緒呼叫該方法,並不會阻塞,只是把計數器減一,如果計數器為0則喚醒被awati()阻塞
的執行緒
CyclicBarrier:加法器
await():計數加1,且阻塞,當計數為指定值時,執行指定執行緒(項楚亡秦)–>解除阻塞
3.執行緒同步
3.1 程式碼塊同步
synchronized實現
synchronized(鎖物件){
同步內容
}
- Lock實現
Lock lock = new ReentrantLock();---產生鎖
lock.lock();--給程式碼手動上鎖
lock.unlock();---在finally中給程式碼解鎖
3.2 方法同步
成員方法的同步:鎖物件是this
靜態方法同步:鎖物件是當前類的類物件
注意:不管什麼同步,多個執行緒之間必須共享同一個鎖物件
3.3 讀寫鎖
synchronized和lock方式一旦上鎖,則多個執行緒併發讀時,只能有一個執行緒讀,不合理
ReadWriteLock loc = new ReentrantReadWriteLock();
loc.readLock().lock();—上讀鎖
loc.readLock().unlock();–解讀鎖
loc.writeLock().lock();–上寫鎖
loc.writeLock().unlock();–解寫鎖
特點:
如果一個執行緒佔有了讀鎖,則其他執行緒申請寫鎖時會一直等待到讀鎖的釋放,其他執行緒只能讀,不能寫
一個執行緒佔用了寫鎖,則其他執行緒在申請讀或寫鎖時都等待釋放寫鎖,不能讀和寫
3.4 Lock和synchronized區別
Lock:是介面,而synchronized是關鍵字
Lock需要手動上鎖和解鎖,而synchronized則自動上鎖和解鎖
Lock在併發讀資料時效率高
3.5 訊號量
作用:用於限制可以訪問資源的數目
用法:
Semaphore sem = new Semaphore(3);—產生一個容納3個併發的訊號量物件
sem.acquire()—申請一個訊號值,每成功申請到一個值,就會自動減一,當為0時申請不到就阻塞
sem.release();–釋放一個訊號值,就是給訊號量加1
3.6 寫時複製
向容器新增元素時,不直接向容器中新增,而是先產生一備份,向備份容器中新增元素,當新增完成後再用備份容器
替換當前容器
CopyOnWriteArrayList–ArrayList
CopyOnWriteArraySet–HashSet
ConcurrentHashMap–HashMap
3.7悲觀鎖與樂觀鎖
悲觀鎖:總是假定最壞情況,每次資料被訪問時,都認為別人要修改,所以其它執行緒在訪問時會阻塞,直到拿
到鎖才解除阻塞,synchronized就是悲觀鎖,lock()也是悲觀鎖。併發時,寫多讀少用悲觀鎖
樂觀鎖:每次其它執行緒訪問時,都認為不會修改資料,所以不上鎖,但是在更新時會判斷一下在次期間是否被
其他執行緒修改過,如果沒有被修改過,則直接覆蓋,如果被修改過則再讀再寫。併發時,讀多寫少用樂觀鎖
java中的CAS技術就是樂觀鎖技術
AtomicInteger:在高併發時修改不會出問題
addAndGet(n)—加n操作,n為負數就是減法,如-1就是每執行一次減1
decrementAndGet()–減1操作
get()—返回資料本身
CAS缺點是迴圈時間長導致開銷大
4.執行緒間通訊
4.1 wait()
呼叫wait方法的程式碼必須放在同步程式碼中
wait會使執行緒處於阻塞狀態
在wait狀態下,如果被請求中斷,會丟擲異常
wait會釋放鎖
4.2 notify()
notify()必須出現在同步程式碼中
notify()會喚醒某一個能過該物件發出的wait()執行緒
notifyAll():會喚醒所有通過該物件發出的wait
notify不會釋放鎖
4.3 Lock實現的執行緒通訊
解決ABCABCABC…問題
通過Lock物件的newCondition()方法產生Condition物件c,
c.awati()會讓執行緒阻塞,c.signal()會讓執行緒喚醒
5.執行緒本地變數ThreadLocal
threadLocal變數為每個執行緒都建立一個副本,每個執行緒在使用變數時,都只能使用自己的變數
6.單例
一個類只能最多產生一個物件,這種類叫單例