電子商務(wù)網(wǎng)站建設(shè)總結(jié)免費(fèi)網(wǎng)站在線觀看人數(shù)在哪直播
1.ReentrantLock
可重入互斥鎖. 和 synchronized 定位類似, 都是用來實(shí)現(xiàn)互斥效果, 保證線程安全.
ReentrantLock 也是可重入鎖. "Reentrant" 這個(gè)單詞的原意就是 "可重入.
?
ReentrantLock 的用法:
- lock(): 加鎖, 如果獲取不到鎖就死等.
- trylock(超時(shí)時(shí)間): 加鎖, 如果獲取不到鎖, 等待一定的時(shí)間之后就放棄加鎖.
- unlock(): 解鎖
?
ReentrantLock lock = new ReentrantLock();-----------------------------------------lock.lock();try {// working} finally {lock.unlock();}
ReentrantLock 和 synchronized 的區(qū)別:
- synchronized 是一個(gè)關(guān)鍵字, 是 JVM 內(nèi)部實(shí)現(xiàn)的(大概率是基于 C++ 實(shí)現(xiàn)). ReentrantLock 是標(biāo)準(zhǔn)庫的一個(gè)類, 在 JVM 外實(shí)現(xiàn)的(基于 Java 實(shí)現(xiàn)).
- synchronized 使用時(shí)不需要手動(dòng)釋放鎖. ReentrantLock 使用時(shí)需要手動(dòng)釋放. 使用起來更靈活,但是也容易遺漏 unlock.
- synchronized 在申請(qǐng)鎖失敗時(shí), 會(huì)死等. ReentrantLock 可以通過 trylock 的方式等待一段時(shí)間就放棄.
- synchronized 是非公平鎖, ReentrantLock 默認(rèn)是非公平鎖. 可以通過構(gòu)造方法傳入一個(gè) true 開啟公平鎖模式.
- 更強(qiáng)大的喚醒機(jī)制. synchronized 是通過 Object 的 wait / notify 實(shí)現(xiàn)等待-喚醒. 每次喚醒的是一個(gè)隨機(jī)等待的線程. ReentrantLock 搭配 Condition 類實(shí)現(xiàn)等待-喚醒, 可以更精確控制喚醒某個(gè)指定的線程
?如何選擇使用哪個(gè)鎖?
- 鎖競(jìng)爭(zhēng)不激烈的時(shí)候, 使用 synchronized, 效率更高, 自動(dòng)釋放更方便.
- 鎖競(jìng)爭(zhēng)激烈的時(shí)候, 使用 ReentrantLock, 搭配 trylock 更靈活控制加鎖的行為, 而不是死等.
- 如果需要使用公平鎖, 使用 ReentrantLock.
既然有了synchronized為啥還有ReentrantLock??
ReentrantLock提供了更豐富的功能!!能做到synchronized做不到的事情!!
1.ReentrantLock 提供了一個(gè)公平鎖的實(shí)現(xiàn)版本~~(構(gòu)造方法中,通過一個(gè)標(biāo)志位,指定是公平鎖,還是非公平鎖)
2.ReentrantLock提供了一個(gè)tryLock操作~~
- trylock 能夠指定一個(gè)加鎖的等待時(shí)間.
- synchronized如果拿不到鎖,就死等..
- trylock 能指定一個(gè)最大的等待時(shí)間~~
?
2.原子類
?
原子類內(nèi)部用的是 CAS 實(shí)現(xiàn),所以性能要比加鎖實(shí)現(xiàn) i++ 高很多。原子類有以下幾個(gè)
- AtomicBoolean
- AtomicInteger
- AtomicIntegerArray
- AtomicLong
- AtomicReference
- AtomicStampedReference
?
以 AtomicInteger 舉例,常見方法有
addAndGet(int delta); i += delta;
decrementAndGet(); --i;
getAndDecrement(); i--;
incrementAndGet(); ++i;
getAndIncrement(); i++;
3.線程池
雖然創(chuàng)建銷毀線程比創(chuàng)建銷毀進(jìn)程更輕量, 但是在頻繁創(chuàng)建銷毀線程的時(shí)候還是會(huì)比較低效.
線程池就是為了解決這個(gè)問題. 如果某個(gè)線程不再使用了, 并不是真正把線程釋放, 而是放到一個(gè) "池子"中, 下次如果需要用到線程就直接從池子中取, 不必通過系統(tǒng)來創(chuàng)建了
ExecutorService 和 Executors
- ExecutorService 表示一個(gè)線程池實(shí)例.
- Executors 是一個(gè)工廠類, 能夠創(chuàng)建出幾種不同風(fēng)格的線程池.
- ExecutorService 的 submit 方法能夠向線程池中提交若干個(gè)任務(wù).
ExecutorService pool = Executors.newFixedThreadPool(10);pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}});
?
Executors 創(chuàng)建線程池的幾種方式
- newFixedThreadPool: 創(chuàng)建固定線程數(shù)的線程池
- newCachedThreadPool: 創(chuàng)建線程數(shù)目動(dòng)態(tài)增長(zhǎng)的線程池.
- newSingleThreadExecutor: 創(chuàng)建只包含單個(gè)線程的線程池.
- newScheduledThreadPool: 設(shè)定 延遲時(shí)間后執(zhí)行命令,或者定期執(zhí)行命令. 是進(jìn)階版的 Timer.
Executors 本質(zhì)上是 ThreadPoolExecutor 類的封裝
ThreadPoolExecutor
ThreadPoolExecutor 提供了更多的可選參數(shù), 可以進(jìn)一步細(xì)化線程池行為的設(shè)定
理解 ThreadPoolExecutor 構(gòu)造方法的參數(shù)
把創(chuàng)建一個(gè)線程池想象成開個(gè)公司. 每個(gè)員工相當(dāng)于一個(gè)線程
- corePoolSize: 正式員工的數(shù)量. (正式員工, 一旦錄用, 永不辭退)
- maximumPoolSize: 正式員工 + 臨時(shí)工的數(shù)目. (臨時(shí)工: 一段時(shí)間不干活, 就被辭退).
- keepAliveTime: 臨時(shí)工允許的空閑時(shí)間.
- unit: keepaliveTime 的時(shí)間單位, 是秒, 分鐘, 還是其他值.
- workQueue: 傳遞任務(wù)的阻塞隊(duì)列
- threadFactory: 創(chuàng)建線程的工廠, 參與具體的創(chuàng)建線程工作.
- RejectedExecutionHandler: 拒絕策略, 如果任務(wù)量超出公司的負(fù)荷了接下來怎么處理.
- AbortPolicy(): 超過負(fù)荷, 直接拋出異常.
- CallerRunsPolicy(): 調(diào)用者負(fù)責(zé)處理
- DiscardOldestPolicy(): 丟棄隊(duì)列中最老的任務(wù).
- DiscardPolicy(): 丟棄新來的任務(wù).
?代碼示例:
ExecutorService pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 3; i++) {pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}});
信號(hào)量 Semaphore
信號(hào)量, 用來表示 "可用資源的個(gè)數(shù)". 本質(zhì)上就是一個(gè)計(jì)數(shù)器.
理解信號(hào)量
可以把信號(hào)量想象成是停車場(chǎng)的展示牌: 當(dāng)前有車位 100 個(gè). 表示有 100 個(gè)可用資源.
當(dāng)有車開進(jìn)去的時(shí)候, 就相當(dāng)于申請(qǐng)一個(gè)可用資源, 可用車位就 -1 (這個(gè)稱為信號(hào)量的 P 操作)
當(dāng)有車開出來的時(shí)候, 就相當(dāng)于釋放一個(gè)可用資源, 可用車位就 +1 (這個(gè)稱為信號(hào)量的 V 操作)
如果計(jì)數(shù)器的值已經(jīng)為 0 了, 還嘗試申請(qǐng)資源, 就會(huì)阻塞等待, 直到有其他線程釋放資源.
?
Semaphore 的 PV 操作中的加減計(jì)數(shù)器操作都是原子的, 可以在多線程環(huán)境下直接使用.
代碼示例:
- 創(chuàng)建 Semaphore 示例, 初始化為 4, 表示有 4 個(gè)可用資源.
- acquire 方法表示申請(qǐng)資源(P操作), release 方法表示釋放資源(V操作)
- 創(chuàng)建 20 個(gè)線程, 每個(gè)線程都嘗試申請(qǐng)資源, sleep 1秒之后, 釋放資源. 觀察程序的執(zhí)行效果.
package thread2;import java.util.concurrent.Semaphore;public class Test10 {public static void main(String[] args) {Semaphore semaphore = new Semaphore(4);Runnable runnable = new Runnable() {@Overridepublic void run() {try {System.out.println("申請(qǐng)資源");semaphore.acquire();System.out.println("我獲取到資源了");Thread.sleep(1000);System.out.println("我釋放資源了");semaphore.release();} catch (InterruptedException e) {e.printStackTrace();}}};for (int i = 0; i < 20; i++) {Thread t = new Thread(runnable);t.start();}}
}
?
CountDownLatch
同時(shí)等待 N 個(gè)任務(wù)執(zhí)行結(jié)束.
好像跑步比賽,10個(gè)選手依次就位,哨聲響才同時(shí)出發(fā);所有選手都通過終點(diǎn),才能公布成績(jī)。
package thread4;import java.util.concurrent.CountDownLatch;public class Test1 {public static void main(String[] args) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(10);for (int i = 0; i < 10; i++) {Thread t = new Thread(() -> {try {Thread.sleep(2);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("選手撞線了!" + Thread.currentThread().getName());countDownLatch.countDown();});t.start();}countDownLatch.await();System.out.println("比賽結(jié)束!");}
}
線程同步的方式有哪些?
synchronized, ReentrantLock, Semaphore 等都可以用于線程同步
?
為什么有了 synchronized 還需要 juc 下的 lock?
以 juc 的 ReentrantLock 為例,
- synchronized 使用時(shí)不需要手動(dòng)釋放鎖. ReentrantLock 使用時(shí)需要手動(dòng)釋放. 使用起來更靈活,
- synchronized 在申請(qǐng)鎖失敗時(shí), 會(huì)死等. ReentrantLock 可以通過 trylock 的方式等待一段時(shí)間就放棄.
- synchronized 是非公平鎖, ReentrantLock 默認(rèn)是非公平鎖. 可以通過構(gòu)造方法傳入一個(gè)true 開啟公平鎖模式.
- synchronized 是通過 Object 的 wait / notify 實(shí)現(xiàn)等待-喚醒. 每次喚醒的是一個(gè)隨機(jī)等待的線程. ReentrantLock 搭配 Condition 類實(shí)現(xiàn)等待-喚醒, 可以更精確控制喚醒某個(gè)指定的線程.
AtomicInteger 的實(shí)現(xiàn)原理是什么?
基于 CAS 機(jī)制. 偽代碼如下:
class AtomicInteger {private int value;public int getAndIncrement() {int oldValue = value;while (CAS(value, oldValue, oldValue + 1) != true) {oldValue = value;}return oldValue;}}
信號(hào)量聽說過么?之前都用在過哪些場(chǎng)景下?
信號(hào)量, 用來表示 "可用資源的個(gè)數(shù)". 本質(zhì)上就是一個(gè)計(jì)數(shù)器.
使用信號(hào)量可以實(shí)現(xiàn) "共享鎖", 比如某個(gè)資源允許 3 個(gè)線程同時(shí)使用, 那么就可以使用 P 操作作為
加鎖, V 操作作為解鎖, 前三個(gè)線程的 P 操作都能順利返回, 后續(xù)線程再進(jìn)行 P 操作就會(huì)阻塞等待,
直到前面的線程執(zhí)行了 V 操作.
解釋一下 ThreadPoolExecutor 構(gòu)造方法的參數(shù)的含義
?
?
?
?
?