摘要:線程池一種線程使用模式。線程池不僅能夠保證內(nèi)核的充分利用,還能防止過(guò)分調(diào)度。相關(guān)起提供了線程池相關(guān)頂級(jí)接口,及子接口和工具類。線程池的最大線程數(shù),要大于。可擴(kuò)容創(chuàng)建一個(gè)可根據(jù)需要線程數(shù),創(chuàng)建新的線程的線程池。
在使用線程時(shí),需要new一個(gè),用完了又要銷毀,這樣頻繁的創(chuàng)建和銷毀很耗資源,所以就提供了線程池。道理和連接池差不多,連接池是為了避免頻繁的創(chuàng)建和釋放連接,所以在連
接池中就有一定數(shù)量的連接,要用時(shí)從連接池拿出,用完歸還給連接池,線程池也一樣。
線程池:一種線程使用模式。線程過(guò)多會(huì)帶來(lái)調(diào)度開銷,進(jìn)而影響緩存局部性和整體性能。而線程池維護(hù)著多
個(gè)線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務(wù)。這避免了在處理短時(shí)間任務(wù)時(shí)創(chuàng)建與銷毀線程的代價(jià)。線程池不僅能夠保證內(nèi)核的充分利用,還能防止過(guò)分調(diào)度。
腦圖:https://www.processon.com/view/link/61849ba4f346fb2ecc4546e5
線程池用法很簡(jiǎn)單,?分為三步。首先用工具類Executors創(chuàng)建線程池,然后給線程池分配任務(wù),最后關(guān)閉線程池就行了。
1 public class ThreadPoolTest { 2 public static void main(String[] args) throws Exception { 3 4 // 1.創(chuàng)建一個(gè) 10 個(gè)線程數(shù)的線程池 5 ExecutorService service = Executors.newFixedThreadPool(10); 6 7 // 2.執(zhí)行一個(gè)Runnable 8 service.execute(new Number1()); 9 10 // 2.提交一個(gè)Callable11 Futurefuture = service.submit(new Number2());12 Integer integer = future.get();13 System.out.println("result = " + integer);14 15 // 關(guān)閉線程池16 service.shutdown();17 }18 }19 20 class Number1 implements Runnable {21 22 @Override23 public void run() {24 System.out.println("----打印Runnable----");25 }26 }27 28 // 10以內(nèi)數(shù)求和29 class Number2 implements Callable {30 private int sum = 0;31 32 @Override33 public Integer call() {34 for (int i = 0; i <= 10; i++) {35 if (i % 2 == 0) {36 sum += i;37 }38 }39 return sum;40 }41 }
注意:線程用完,要關(guān)閉線程池,否則程序依然在運(yùn)行中。
JDK 5.0 起提供了線程池相關(guān)API:頂級(jí)接口Executor,及子接口 ExecutorService 和工具類Executors。
JUC包描述:圖片來(lái)源API文檔
Executors:工具類,線程池的工廠類,用于創(chuàng)建并返回不同類型的線程池。
1 // 一池N線程:創(chuàng)建一個(gè)固定(可重用)線程數(shù)的線程池。 2 ExecutorService Executors.newFixedThreadPool(int nThreads) 3 4 // 一池一線程:創(chuàng)建一個(gè)只有一個(gè)線程的線程池。 5 ExecutorService Executors.newSingleThreadExecutor() 6 7 // 可擴(kuò)容:創(chuàng)建一個(gè)可根據(jù)需要線程數(shù),創(chuàng)建新的線程的線程池。 8 ExecutorService Executors.newCachedThreadPool() 9 10 // 可用于調(diào)度:創(chuàng)建一個(gè)線程池,它可安排在給定延遲后運(yùn)行命令或者定期的執(zhí)行。11 ScheduledExecutorService Executors.newScheduledThreadPool(int corePoolSize)
ExecutorService:
1 // 執(zhí)行任務(wù)/命令,沒(méi)有返回值,一般用來(lái)執(zhí)行Runnable 2 void execute(Runnable command) 3 4 // 可用于提交一個(gè)Runnable,但沒(méi)有返回值 5 Future> submit(Runnable task) 6 7 // 執(zhí)行任務(wù),有返回值,一般用來(lái)執(zhí)行Callable 8Future submit(Callable task) 9 10 // 關(guān)閉連接池11 void shutdown()
代碼示例:創(chuàng)建固定 5 個(gè)線程的線程池為 10 個(gè)任務(wù)服務(wù)。
1 public class ThreadPoolTest { 2 public static void main(String[] args) { 3 // 1.創(chuàng)建一個(gè) 10 個(gè)線程數(shù)的線程池 4 ExecutorService service = Executors.newFixedThreadPool(5); 5 6 try { 7 for (int i = 0; i < 10; i++) { 8 int finalI = i; 9 service.execute(() -> {10 11 System.out.println(Thread.currentThread().getName() + " 為客戶 " + finalI + " 辦理業(yè)務(wù)~");12 13 // try {14 // Thread.sleep(1000_000);15 // } catch (InterruptedException e) {16 // e.printStackTrace();17 // }18 19 });20 }21 } finally {22 service.shutdown();23 }24 }25 }26 27 // 可能的一種結(jié)果28 pool-1-thread-1 為客戶 0 辦理業(yè)務(wù)~29 pool-1-thread-2 為客戶 1 辦理業(yè)務(wù)~30 pool-1-thread-2 為客戶 6 辦理業(yè)務(wù)~31 pool-1-thread-2 為客戶 7 辦理業(yè)務(wù)~32 pool-1-thread-2 為客戶 8 辦理業(yè)務(wù)~33 pool-1-thread-1 為客戶 5 辦理業(yè)務(wù)~34 pool-1-thread-2 為客戶 9 辦理業(yè)務(wù)~35 pool-1-thread-3 為客戶 2 辦理業(yè)務(wù)~36 pool-1-thread-4 為客戶 3 辦理業(yè)務(wù)~37 pool-1-thread-5 為客戶 4 辦理業(yè)務(wù)~
可以看到,銀行 5 個(gè)窗口為 10 個(gè)客戶相繼服務(wù)。若前面服務(wù)時(shí)間長(zhǎng)(打開注釋),線程池便沒(méi)有新的線程來(lái)執(zhí)行任務(wù)了。程序會(huì)陷入等待中。
代碼示例:創(chuàng)建單個(gè)線程的線程池為 10 個(gè)線程服務(wù)。代碼同上,只修改:
1 ExecutorService service = Executors.newSingleThreadExecutor();
代碼示例:創(chuàng)建可擴(kuò)容線程的線程池為 10 個(gè)線程服務(wù)。代碼同上,只修改:
1 ExecutorService service = Executors.newCachedThreadPool();
為什么要用線程池管理線程呢?當(dāng)然是為了線程復(fù)用。
背景:經(jīng)常創(chuàng)建和銷毀、使用量特別大的資源,比如并發(fā)情況下的線程,對(duì)性能影響很大。
思路:提前創(chuàng)建好多個(gè)線程,放入線程池中,使用時(shí)直接獲取,使用完放回池中。可以避免頻繁的創(chuàng)建和銷毀,實(shí)現(xiàn)重復(fù)利用。類似生活中的公共交通工具。
好處:提高響應(yīng)速度(減少了創(chuàng)建新線程的時(shí)間);降低資源消耗(重復(fù)利用線程池中線程,不需要每次都創(chuàng)建);便于線程管理。
前面介紹了三種(固定數(shù)、單一的、可變的)創(chuàng)建線程池的方式,實(shí)際工作用哪一個(gè)呢?都不使用!為什么呢?
《阿里巴巴Java開發(fā)手冊(cè)》明確規(guī)定:線程池不允許使用Executors創(chuàng)建,而是通過(guò)ThreadPoolExecutor的方式,規(guī)避資源耗盡風(fēng)險(xiǎn)。
查看源碼,可以看到,用Executors創(chuàng)建線程池的三種方式中,都 new 了一個(gè) ThreadPoolExecutor。所以,實(shí)際生產(chǎn)一般通過(guò) ThreadPoolExecutor 的 7 個(gè)參數(shù),自定義線程池。
源碼示例:7 個(gè)參數(shù)的構(gòu)造器。
1 public ThreadPoolExecutor(int corePoolSize, 2 int maximumPoolSize, 3 long keepAliveTime, 4 TimeUnit unit, 5 BlockingQueueworkQueue, 6 ThreadFactory threadFactory, 7 RejectedExecutionHandler handler) { 8 if (corePoolSize < 0 || 9 maximumPoolSize <= 0 ||10 maximumPoolSize < corePoolSize ||11 keepAliveTime < 0)12 throw new IllegalArgumentException();13 if (workQueue == null || threadFactory == null || handler == null)14 throw new NullPointerException();15 this.corePoolSize = corePoolSize;16 this.maximumPoolSize = maximumPoolSize;17 this.workQueue = workQueue;18 this.keepAliveTime = unit.toNanos(keepAliveTime);19 this.threadFactory = threadFactory;20 this.handler = handler;21 }
介紹線程池之前,先來(lái)看一個(gè)生活中的案例。銀行業(yè)務(wù)辦理流程,如圖:
某銀行一共有 5 個(gè)服務(wù)窗口,但平時(shí)一般只開放兩個(gè),另外三個(gè)不開放。大廳中還有 10 個(gè)等待服務(wù)的座位。某天:
(1)客人1(用Thread1表示)來(lái)辦理業(yè)務(wù),他就直接去開放的窗口1辦理(假設(shè)他需要服務(wù)的時(shí)間很長(zhǎng),一直在服務(wù)中,后面的也一樣)。
(2)Thread2來(lái)辦理業(yè)務(wù),由于窗口1在服務(wù)中,所以他去了開放的窗口2辦理。
(3)Thread3來(lái)辦理業(yè)務(wù),由于窗口1和窗口2都在服務(wù)中,所以他去了大廳的等待服務(wù)座位上排隊(duì)等待。
(4)Thread4~Thread12 同理Thread3。
(5)Thread13來(lái)辦理業(yè)務(wù),由于窗口1和窗口2都在服務(wù)中,且此時(shí)大廳的等待座位上也已滿。銀行經(jīng)理便將關(guān)閉的窗口3打開來(lái)為Thread13服務(wù)。注意:這里并不是Thread13去大廳排隊(duì),然后隊(duì)列中隊(duì)頭元素Thread3出隊(duì)接受服務(wù)。而是直接為Thread13服務(wù)。
(6)Thread14,Thread15來(lái)辦理業(yè)務(wù),會(huì)開放窗口4為Thread14服務(wù),開放窗口5為Thread15服務(wù)。
(7)Thread16來(lái)辦理業(yè)務(wù),此時(shí),已無(wú)可用窗口,且大廳的等待座位上也已滿。銀行便拒絕再為 Thread16 服務(wù)。
說(shuō)明:若 Thread13、Thread14、Thread15 業(yè)務(wù)辦理完畢后,沒(méi)有新的客人來(lái)銀行辦理業(yè)務(wù)。那么窗口3、窗口4、窗口5會(huì)在一定時(shí)間后又關(guān)閉起來(lái)。
下面介紹 ThreadPoolExecutor 構(gòu)造器中的 7 個(gè)核心參數(shù)。
corePoolSize:線程池的核心線程數(shù)。
maximumPoolSize:線程池的最大線程數(shù),要大于corePoolSize。
keepAliveTime:非核心線程閑置下來(lái)最多存活的時(shí)間。
unit:線程池中非核心線程保持存活的時(shí)間單位,與keepAliveTime一起使用。
workQueue:用來(lái)保存提交后,等待執(zhí)行任務(wù)的阻塞隊(duì)列。
threadFactory:創(chuàng)建線程的工廠類。
handler:拒絕策略。
在理解上一節(jié)"銀行服務(wù)"的過(guò)程后,就不難理解上面 7 個(gè)參數(shù)的含義。
corePoolSize = 2:窗口1 + 窗口2。
maximumPoolSize = 5:窗口1 + 窗口2 + 窗口3 + 窗口4 + 窗口5。
workQueue = 10:銀行大廳排隊(duì)隊(duì)列的大小。關(guān)于阻塞隊(duì)列 BlockingQueue
keepAliveTime + unit:"窗口3、窗口4、窗口5會(huì)在一定時(shí)間后又關(guān)閉起來(lái)"的時(shí)間。
handler:"銀行便拒絕再為 Thread16 服務(wù)"的拒絕方式。
在了解 ThreadPoolExecutor 7個(gè)核心參數(shù)的作用后,再看Executors創(chuàng)建的三種線程池的源碼,就不難理解他們的作用。也就明白為什么《阿里巴巴Java開發(fā)手冊(cè)》中禁止使用Executors創(chuàng)建,而要使用ThreadPoolExecutor自定義線程池。
源碼示例:
一池N線程:創(chuàng)建一個(gè)固定(可重用)線程數(shù)的線程池。
1 ExecutorService Executors.newFixedThreadPool(int nThreads); 2 3 public static ExecutorService newFixedThreadPool(int nThreads) { 4 return new ThreadPoolExecutor(nThreads, nThreads, 5 0L, TimeUnit.MILLISECONDS, 6 new LinkedBlockingQueue()); 7 } 8 9 public LinkedBlockingQueue() {10 this(Integer.MAX_VALUE);11 }
一池一線程:創(chuàng)建一個(gè)只有一個(gè)線程的線程池。
1 ExecutorService Executors.newSingleThreadExecutor(); 2 3 public static ExecutorService newSingleThreadExecutor() { 4 return new FinalizableDelegatedExecutorService 5 (new ThreadPoolExecutor(1, 1, 6 0L, TimeUnit.MILLISECONDS, 7 new LinkedBlockingQueue())); 8 } 9 10 public LinkedBlockingQueue() {11 this(Integer.MAX_VALUE);12 }
可擴(kuò)容:創(chuàng)建一個(gè)可根據(jù)需要線程數(shù),創(chuàng)建新的線程的線程池。
1 ExecutorService Executors.newCachedThreadPool();2 3 public static ExecutorService newCachedThreadPool() {4 return new ThreadPoolExecutor(0, Integer.MAX_VALUE,5 60L, TimeUnit.SECONDS,6 new SynchronousQueue());7 }
在理解"銀行服務(wù)"的過(guò)程后,其實(shí)也就說(shuō)清楚了線程池的工作流程。只是一些細(xì)節(jié)沒(méi)有說(shuō),比如:
(1)窗口3為Thread13服務(wù)完成后,Thread14才來(lái),情況如何?
(2)……
代碼示例:銀行 2+3 個(gè)窗口為陸續(xù)來(lái)的 16 個(gè)客戶服務(wù)。
1 public class ThreadPoolDemo { 2 public static void main(String[] args) throws Exception { 3 // 模擬上圖中 2 + 3 + 10(大廳排隊(duì)長(zhǎng)度) 的線程池 4 ThreadPoolExecutor executor = new ThreadPoolExecutor( 5 2, 5 6 , 6, TimeUnit.SECONDS 7 , new ArrayBlockingQueue<>(10) 8 , Executors.defaultThreadFactory() 9 , new ThreadPoolExecutor.AbortPolicy());10 11 // 創(chuàng)建16個(gè)線程模擬16個(gè)客戶12 final int num = 16;13 for (int i = 1; i <= num; i++) {14 int finalI = i;15 16 // 這里主要為了給線程起名字.17 Thread thread = new Thread(() -> {18 System.out.println(Thread.currentThread().getName() + "=====" + finalI + " 號(hào)客人開始服務(wù)");19 20 // 假設(shè) 13 和 16 服務(wù)很快.21 if (finalI != 16 && finalI != 13) {22 try {23 // 正在為 finalI 號(hào)客戶服務(wù)中24 Thread.sleep(1000_000);25 } catch (InterruptedException e) {26 e.printStackTrace();27 }28 }29 30 System.out.println(Thread.currentThread().getName() + "=====" + finalI + " 號(hào)客人服務(wù)結(jié)束");31 }, "------" + i);32 33 System.out.println(thread.getName() + " 號(hào)客人來(lái)了");34 executor.execute(thread);35 36 // 讓主線程休息一下,保證上面開啟的線程先執(zhí)行.37 Thread.sleep(200);38 }39 40 // 保證上面的線程執(zhí)行完41 Thread.sleep(1_000);42 43 System.out.println("===核心線程數(shù)===" + executor.getCorePoolSize());44 System.out.println("===總?cè)蝿?wù)數(shù)=====" + executor.getTaskCount());45 46 final BlockingQueuequeue = executor.getQueue();47 System.out.println("===正在排隊(duì)====" + queue.size());48 49 System.out.println("===最大線程數(shù)===" + executor.getMaximumPoolSize());50 System.out.println("==============" + executor.getPoolSize());51 System.out.println("===完成任務(wù)數(shù)===" + executor.getCompletedTaskCount());52 System.out.println("==============" + executor.getLargestPoolSize());53 54 executor.shutdown();55 }56 }57 58 // 結(jié)果(程序未停止)59 ------1 號(hào)客人來(lái)了60 pool-1-thread-1=====1 號(hào)客人開始服務(wù)61 ------2 號(hào)客人來(lái)了62 pool-1-thread-2=====2 號(hào)客人開始服務(wù)63 ------3 號(hào)客人來(lái)了64 ------4 號(hào)客人來(lái)了65 ------5 號(hào)客人來(lái)了66 ------6 號(hào)客人來(lái)了67 ------7 號(hào)客人來(lái)了68 ------8 號(hào)客人來(lái)了69 ------9 號(hào)客人來(lái)了70 ------10 號(hào)客人來(lái)了71 ------11 號(hào)客人來(lái)了72 ------12 號(hào)客人來(lái)了 // 到這里都不難理解73 ------13 號(hào)客人來(lái)了74 pool-1-thread-3=====13 號(hào)客人開始服務(wù)75 pool-1-thread-3=====13 號(hào)客人服務(wù)結(jié)束 // 開放窗口3為客戶13立刻服務(wù)完畢.76 pool-1-thread-3=====3 號(hào)客人開始服務(wù) // 阻塞隊(duì)列,隊(duì)頭 客戶3 出隊(duì)接受窗口3的服務(wù)77 ------14 號(hào)客人來(lái)了 // 加入阻塞隊(duì)列隊(duì)尾78 ------15 號(hào)客人來(lái)了79 pool-1-thread-4=====15 號(hào)客人開始服務(wù)80 ------16 號(hào)客人來(lái)了81 pool-1-thread-5=====16 號(hào)客人開始服務(wù)82 pool-1-thread-5=====16 號(hào)客人服務(wù)結(jié)束83 pool-1-thread-5=====4 號(hào)客人開始服務(wù)84 ===核心線程數(shù)===285 ===總?cè)蝿?wù)數(shù)=====1686 ===正在排隊(duì)====987 ===最大線程數(shù)===588 ==============589 ===完成任務(wù)數(shù)===290 ==============5
其他的情況,可通過(guò)修改代碼示例中相關(guān)參數(shù)進(jìn)行測(cè)試,自然就理解。
線程在Java中屬于稀缺資源,線程池不是越大越好,也不是越小越好。那么,線程池的參數(shù)要如何設(shè)置才合理呢?
任務(wù)分為CPU密集型、IO密集型、混合型。
CPU密集型:大部分都在用CPU跟內(nèi)存,加密,邏輯操作,業(yè)務(wù)處理等。
IO密集型:數(shù)據(jù)庫(kù)鏈接,網(wǎng)絡(luò)通訊傳輸?shù)取?br> CPU密集型:一般推薦線程池不要過(guò)大,一般是CPU數(shù) + 1,+1是因?yàn)榭赡艽嬖陧?yè)缺失(就是可能存在有些數(shù)據(jù)在硬盤中需要多來(lái)一個(gè)線程將數(shù)據(jù)讀入內(nèi)存)。如果線程池?cái)?shù)太大,可能會(huì)頻繁的進(jìn)行線程上下文切換跟任務(wù)調(diào)度。
獲得當(dāng)前CPU核心數(shù)代碼如下:
1 Runtime.getRuntime().availableProcessors();
IO密集型:線程數(shù)適當(dāng)大一點(diǎn),機(jī)器的CPU核心數(shù)*2。
混合型:可以考慮根絕情況將它拆分成CPU密集型和IO密集型任務(wù),如果執(zhí)行時(shí)間相差不大,拆分可以提升吞吐量,反之沒(méi)有必要。
當(dāng)線程池的任務(wù)緩存隊(duì)列已滿并且線程池中的線程數(shù)目達(dá)到maximumPoolSize,如果還有任務(wù)到來(lái)就會(huì)采取任務(wù)拒絕策略,就會(huì)調(diào)用這個(gè)接口里的這個(gè)方法。也就是"銀行便拒絕再為 Thread16 服務(wù)"的拒絕方式。
1 public interface RejectedExecutionHandler {2 void rejectedExecution(Runnable r, ThreadPoolExecutor executor);3 }
ThreadPoolExecutor 提供了四種拒絕策略,分別是
AbortPolicy:直接拋出異常,這也是默認(rèn)策略。
CallerRunsPolicy:返回給調(diào)用者處理。用調(diào)用者所在線程來(lái)運(yùn)行任務(wù)。
DiscardOldestPolicy:拋棄隊(duì)列中等待最久的任務(wù),然后把當(dāng)前任務(wù)加入隊(duì)列中嘗試再次提交當(dāng)前任務(wù)。
DiscardPolicy:不處理,直接丟棄當(dāng)前任務(wù)。
代碼示例:4種拒絕策略,代碼同上,只需修改:
1 // 1.去掉這個(gè)if條件 2 if (finalI != 16 && finalI != 13) {} 3 4 5 6 // 2.1 線程池創(chuàng)建時(shí)拒絕策略為: 7 new ThreadPoolExecutor.AbortPolicy() 8 // 2.1 結(jié)果,直接拋出了異常.(只截取了最后一點(diǎn)) 9 ------16 號(hào)客人來(lái)了10 Exception in thread "main" java.util.concurrent.RejectedExecutionException11 12 13 14 // 2.2 線程池創(chuàng)建時(shí)拒絕策略為:15 new ThreadPoolExecutor.CallerRunsPolicy()16 // 2.2 結(jié)果,返回給調(diào)用者main處理了.(只截取了最后一點(diǎn))17 ------16 號(hào)客人來(lái)了18 main=====16 號(hào)客人開始服務(wù)19 20 21 22 // 2.3 線程池創(chuàng)建時(shí)拒絕策略為:23 new ThreadPoolExecutor.DiscardOldestPolicy()24 // 2.3 結(jié)果,見下圖25 26 27 28 // 2.4 線程池創(chuàng)建時(shí)拒絕策略為:29 new ThreadPoolExecutor.DiscardPolicy()30 // 2.4 結(jié)果(丟棄了任務(wù),沒(méi)有任何處理)
?
通過(guò)debug斷點(diǎn)的方式,可以查看到:DiscardOldestPolicy策略中,此時(shí)阻塞隊(duì)列中是客戶4~客戶16。也就是客戶3 出隊(duì),被拋棄,客戶16入隊(duì)等待。
如果不使用線程池提供的4種拒絕策略,也可以自己實(shí)現(xiàn)拒絕策略的接口,實(shí)現(xiàn)對(duì)這些超出數(shù)量的任務(wù)的處理。比如:為被拒絕的任務(wù)開啟一個(gè)新的線程執(zhí)行,如下。
1 // 線程池創(chuàng)建時(shí)拒絕策略為: 2 new MyRejectedExecutionHandler() 3 // 結(jié)果 4 ------16 號(hào)客人來(lái)了 5 ---開啟新線程處理任務(wù)---=====16 號(hào)客人開始服務(wù) 6 7 8 // 自定義的策略拒絕 9 class MyRejectedExecutionHandler implements RejectedExecutionHandler {10 11 @Override12 public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {13 new Thread(r, "---開啟新線程處理任務(wù)---").start();14 }15 }
參考文檔:https://www.matools.com/api/java8
《阿里巴巴Java開發(fā)手冊(cè)》百度網(wǎng)盤:https://pan.baidu.com/s/1FZ9DNr0sF1mAc6Nq_6QZmg? ? 密碼: 4sw1
作者:Craftsman-L
本博客所有文章僅用于學(xué)習(xí)、研究和交流目的,版權(quán)歸作者所有,歡迎非商業(yè)性質(zhì)轉(zhuǎn)載。
如果本篇博客給您帶來(lái)幫助,請(qǐng)作者喝杯咖啡吧!點(diǎn)擊下面打賞,您的支持是我最大的動(dòng)力!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/123754.html
摘要:這里呢,我直接給出高并發(fā)場(chǎng)景通常都會(huì)考慮的一些解決思路和手段結(jié)尾如何有效的準(zhǔn)備面試中并發(fā)類問(wèn)題,我已經(jīng)給出我的理解。 showImg(https://segmentfault.com/img/bV7Viy?w=550&h=405); 主題 又到面試季了,從群里,看到許多同學(xué)分享了自己的面試題目,我也抽空在網(wǎng)上搜索了一些許多公司使用的面試題,目前校招和社招的面試題基本都集中在幾個(gè)大方向上...
摘要:在中一般來(lái)說(shuō)通過(guò)來(lái)創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說(shuō)明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細(xì)原理解析 - 后端 - 掘金今天我們來(lái)研究學(xué)習(xí)一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個(gè)類所提供的隊(duì)列式...
摘要:在中一般來(lái)說(shuō)通過(guò)來(lái)創(chuàng)建所需要的線程池,如高并發(fā)原理初探后端掘金閱前熱身為了更加形象的說(shuō)明同步異步阻塞非阻塞,我們以小明去買奶茶為例。 AbstractQueuedSynchronizer 超詳細(xì)原理解析 - 后端 - 掘金今天我們來(lái)研究學(xué)習(xí)一下AbstractQueuedSynchronizer類的相關(guān)原理,java.util.concurrent包中很多類都依賴于這個(gè)類所提供的隊(duì)列式...
摘要:當(dāng)活動(dòng)線程核心線程非核心線程達(dá)到這個(gè)數(shù)值后,后續(xù)任務(wù)將會(huì)根據(jù)來(lái)進(jìn)行拒絕策略處理。線程池工作原則當(dāng)線程池中線程數(shù)量小于則創(chuàng)建線程,并處理請(qǐng)求。當(dāng)線程池中的數(shù)量等于最大線程數(shù)時(shí)默默丟棄不能執(zhí)行的新加任務(wù),不報(bào)任何異常。 spring-cache使用記錄 spring-cache的使用記錄,坑點(diǎn)記錄以及采用的解決方案 深入分析 java 線程池的實(shí)現(xiàn)原理 在這篇文章中,作者有條不紊的將 ja...
閱讀 756·2023-04-26 01:30
閱讀 3306·2021-11-24 10:32
閱讀 2192·2021-11-22 14:56
閱讀 1988·2021-11-18 10:07
閱讀 561·2019-08-29 17:14
閱讀 631·2019-08-26 12:21
閱讀 3110·2019-08-26 10:55
閱讀 2945·2019-08-23 18:09