日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java线程和线程池的使用

發(fā)布時間:2023/12/20 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java线程和线程池的使用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java線程和線程池

一、創(chuàng)建多線程的方式

????java多線程非經(jīng)常見。怎樣使用多線程,怎樣創(chuàng)建線程。java中有兩種方式,第一種是讓自己的類實現(xiàn)Runnable接口。另外一種是讓自己的類繼承Thread類。事實上Thread類自己也是實現(xiàn)了Runnable接口。

詳細使用實比例如以下:

1、通過實現(xiàn)Runnable接口方式

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 publicclassMyThread1?implementsRunnable//通過實現(xiàn)Runnable接口方式 { ????String sign =?"thread#1@"; ????@Override ????publicvoidrun() ????{ ????????for(inti =?0; i <?30; i++) ????????{ ????????????System.out.println(sign +?"->"+ i); ????????????try ????????????{ ????????????????Thread.sleep(100L); ????????????}?catch(InterruptedException e) ????????????{ ????????????????e.printStackTrace(); ????????????} ????????} ????} }

2、通過繼承Thread類的方式

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 publicclassMyThread2?extendsThread//通過繼承Thread類的方式 { ????String sign =?"thread#2@"; ????@Override ????publicvoidrun() ????{ ????????for(inti =?0; i <?30; i++) ????????{ ????????????System.out.println(sign +?"->"+ i); ????????????try ????????????{ ????????????????Thread.sleep(100L); ????????????}?catch(InterruptedException e) ????????????{ ????????????????e.printStackTrace(); ????????????} ????????} ????} }

????再啟用上面創(chuàng)建的兩種線程,調(diào)運代碼例如以下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 publicstaticvoidmain(String[] args)?throwsInterruptedException { ????longstartTime = System.currentTimeMillis(); ????// 通過主線程啟動自己的線程 ????// 通過實現(xiàn)runnable接口 ????Runnable myThread1 =?newMyThread1(); ????Thread thread1 =?newThread(myThread1); ????thread1.start(); ????// 通過繼承thread類 ????Thread thread2 =?newThread(newMyThread2()); ????thread2.start(); ????// 注意這里不是調(diào)運run()方法,而是調(diào)運線程類Thread的start方法。在Thread方法內(nèi)部。會調(diào)運本地系統(tǒng)方法。終于會自己主動調(diào)運自己線程類的run方法 ????// 讓主線程睡眠 ????Thread.sleep(1000L); ????System.out.println("主線程結(jié)束!用時:" ????????????+ (System.currentTimeMillis() - startTime)); ????// System.exit(0); }

????輸入結(jié)果(每次輸入可能不同)不再具體列出。對于上面的兩種方式。更推薦使用實現(xiàn)Runnable接口的方式實現(xiàn)多線程。一方面是能夠防止java單繼承的顧慮。還有一方面Runnable是面向接口編程。擴展性比起繼承Thread更好。

所以盡量使用implement Runnable的方式。

?

二、java線程類型說明

????上面是將多線程跑起來了,可是有個問題。假設(shè)不讓主線程睡眠。當(dāng)主線程(比方main線程)結(jié)束以后。假設(shè)子線程還沒結(jié)束。那么子線程是否還會執(zhí)行呢?答案是會繼續(xù)執(zhí)行,為了說明這個問題。就又涉及到j(luò)ava中線程的類型。

java中線程一共同擁有兩種類型:守護線程(daemon thread)和用戶線程(user thread)又叫非守護線程。

能夠通過thread.setDaemon()方法設(shè)置線程是否為守護線程。默認是設(shè)置非守護線程(false)。java虛擬機停止執(zhí)行的時間是虛擬機中執(zhí)行的全部線程都是守護線程的時候,也就是說假設(shè)jvm中沒有user thread的時候,jvm就停止執(zhí)行。或者說jvm在最后一個非守護線程結(jié)束的時候,將停止全部的守護進程,然后退出jvm。

????當(dāng)使用main方法開啟線程時,主線程默認是非守護進程,而用戶自己開的進程也是非守護進程。

當(dāng)主線程結(jié)束,可是子線程(默認是非守護線程)還沒結(jié)束,所以虛擬機是不停止執(zhí)行的,當(dāng)子線程執(zhí)行完以后。假設(shè)主線程也執(zhí)行完成,jvm發(fā)現(xiàn)沒有非守護線程,就將jvm關(guān)閉,所以當(dāng)main方法的主線程執(zhí)行完成以后,子線程是會繼續(xù)執(zhí)行的。

當(dāng)然我們也能夠讓在main主線程執(zhí)行完成以后,子線程不再執(zhí)行。方法就是將全部的子線程設(shè)置為守護進程setDaemon(true)就可以。

可是須要注意的是這個設(shè)置須要在線程執(zhí)行之前設(shè)置,不能在線程執(zhí)行的過程中改動線程類型。

????更直白點說假設(shè)用戶將線程設(shè)置為守護進程。那實際的意思就是告訴jvm你不用搭理我這個線程,jvm想停止的時候,不用考慮我這個線程是否運行結(jié)束。這樣的線程詳細的使用比方在垃圾回收機制的線程。就是一個守護線程。

1 2 3 4 5 6 7 8 9 10 11 12 13 Runnable myThread1 =?newMyThread1(); Thread thread1 =?newThread(myThread1); thread1.setDaemon(true); thread1.start(); Thread thread2 =?newThread(newMyThread2()); thread2.setDaemon(false); thread2.start(); System.out.println("mainThread isDaemon:" ????????+ Thread.currentThread().isDaemon()); System.out.println("thread1 isDaemon:"+ thread1.isDaemon()); System.out.println("thread2 isDaemon:"+ thread2.isDaemon());

?

三、線程池的使用

????上面已經(jīng)看過了能夠在代碼中直接新起線程。假設(shè)我們在主線程中新起一百個線程。讓這一百個線程同一時候工作,邏輯上是沒有不論什么問題的。可是這樣做對系統(tǒng)資源的開銷非常大,這樣會在短時間內(nèi)處理非常多的任務(wù),當(dāng)然包含新起線程等等。基于這種考慮,我們是有必要引入線程池這個東西的。線程池就是一個池子,池子里有非常多可用線程資源,假設(shè)須要就直接從這個池子里拿就是。

當(dāng)不用的時候。放入池子中,線程池會自己主動幫我們管理。所以使用線程池主要有下面兩個優(yōu)點:1、降低在創(chuàng)建和銷毀線程上所花的時間以及系統(tǒng)資源的開銷?2、如不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量線程而導(dǎo)致消耗完系統(tǒng)內(nèi)存?。

????假設(shè)我們想要使用線程池,就須要先定義這個線程池。定義線程池的時候,當(dāng)中的幾個主要參數(shù)說明例如以下:
-corePoolSize(int):線程池中保持的線程數(shù)量。包含空暇線程在內(nèi)。也就是線程池釋放的最小線程數(shù)量界限。

-maximumPoolSize(int):線程池中嫩容納最大線程數(shù)量。

-keepAliveTime(long):空暇線程保持在線程池中的時間。當(dāng)線程池中線程數(shù)量大于corePoolSize的時候。

-unit(TimeUnit枚舉類):上面參數(shù)時間的單位。能夠是分鐘。秒,毫秒等等。

-workQueue(BlockingQueue<Runnable>):任務(wù)隊列,當(dāng)線程任務(wù)提交到線程池以后,首先放入隊列中,然后線程池依照該任務(wù)隊列依次運行對應(yīng)的任務(wù)。

能夠使用的workQueue有非常多,比方:LinkedBlockingQueue等等。

-threadFactory(ThreadFactory類):新線程產(chǎn)生工廠類。

-handler(RejectedExecutionHandler類):當(dāng)提交線程拒絕運行、異常的時候。處理異常的類。

該類取值例如以下:(注意都是內(nèi)部類)

ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。 ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),可是不拋出異常。 ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù)。然后又一次嘗試運行任務(wù),反復(fù)此過程。

ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。

???除了自己定義線程池以外,?java提供了幾種經(jīng)常使用的線程池,能夠快捷的供程序猿使用,他們各自是:

1、newFixedThreadPool?創(chuàng)建固定大小數(shù)量線程池,數(shù)量通過傳入的參數(shù)決定。

2、newSingleThreadExecutor?創(chuàng)建一個線程容量的線程池,全部的線程依次運行,相當(dāng)于創(chuàng)建固定數(shù)量為1的線程池。

3、newCachedThreadPool?創(chuàng)建可緩存的線程池,沒有最大線程限制(實際上是Integer.MAX_VALUE)。假設(shè)用空暇線程等待時間超過一分鐘,就關(guān)閉該線程。

4、newScheduledThreadPool?創(chuàng)建計劃(延遲)任務(wù)線程池,線程池中的線程能夠讓其在特定的延遲時間之后運行,也能夠以固定的時間反復(fù)運行(周期性運行)。

相當(dāng)于曾經(jīng)的Timer類的使用。
5、newSingleThreadScheduledExecutor?創(chuàng)建單線程池延遲任務(wù),創(chuàng)建一個線程容量的計劃任務(wù)。

????事實上通過靜態(tài)方法創(chuàng)建的上面幾種線程池,也都是通過傳入默認的各個參數(shù)。然后返回一個有各自特點的線程池。詳細參數(shù)能夠通過查看jdk源代碼閱讀。

????有了線程池。那么我們怎樣利用線程池中線程運行我們的任務(wù),因為Java將線程池的封裝,我們拿到的線程池的線程事實上是一個包括線程任務(wù)的運行器,僅僅須要調(diào)運運行器的運行方法,就會自己主動運行我們線程中的任務(wù)。對于非計劃任務(wù),我們須要拿到一個ThreadPoolExecutor,對于計劃任務(wù)。我們須要拿到一個ScheduledThreadPoolExecutor(它是ThreadPoolExecutor的子類)。在了解這兩個類之前。須要先了解兩個接口,ExecutorService以及它的子接口ScheduleThreadExecutorService接口。上面兩個接口分別實現(xiàn)了這兩個接口,這個兩接口定義了execute(Runnable r)方法,這種方法去運行線程的任務(wù)。

也就是我們通過調(diào)運ThreadPoolExecutor或者ScheduledThreadPoolExecutor的execute(Runnable r)方法開啟我們的線程,而且運行我們的線程任務(wù),詳細代碼例如以下:

????定義一個單例的線程池:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 publicclassMyPool { ????privatestaticMyPool myPool =?null; ????//單例線程池中有兩種詳細的線程池 ????privateThreadPoolExecutor threadPool =?null; ????privateScheduledThreadPoolExecutor scheduledPool =?null; ????publicThreadPoolExecutor getThreadPool() ????{ ????????returnthreadPool; ????} ????publicScheduledThreadPoolExecutor getScheduledPool() ????{ ????????returnscheduledPool; ????} ????//設(shè)置線程池的各個參數(shù)的大小 ????privateintcorePoolSize =?10;// 池中所保存的線程數(shù),包含空暇線程。 ????privateintmaximumPoolSize =?20;// 池中同意的最大線程數(shù)。

????privatelongkeepAliveTime =?3;// 當(dāng)線程數(shù)大于核心時,此為終止前多余的空暇線程等待新任務(wù)的最長時間。 ????privateintscheduledPoolSize =?10; ????privatestaticsynchronizedvoidcreate() ????{ ????????if(myPool ==?null) ????????????myPool =?newMyPool(); ????} ????publicstaticMyPool getInstance() ????{ ????????if(myPool ==?null) ????????????create(); ????????returnmyPool; ????} ????privateMyPool() ????{ ????????//實例化線程池。這里使用的LinkedBlockingQueue作為workQueue。使用DiscardOldestPolicy作為handler ????????this.threadPool =?newThreadPoolExecutor(corePoolSize, maximumPoolSize, ????????????????keepAliveTime, TimeUnit.SECONDS, ????????????????newLinkedBlockingQueue<Runnable>(), ????????????????newThreadPoolExecutor.DiscardOldestPolicy()); ????????//實例化計劃任務(wù)線程池 ????????this.scheduledPool =?newScheduledThreadPoolExecutor(scheduledPoolSize); ????} }

????獲取線程池中的線程,而且運行線程中任務(wù):

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Test publicvoidtestThreadPool() { ????ThreadPoolExecutor pool1 = (ThreadPoolExecutor) Executors ????????????.newCachedThreadPool(); ????pool1.execute(newRunnable() ????{ ????????@Override ????????publicvoidrun() ????????{ ????????????System.out.println("快捷線程池中的線程!

"

); ????????} ????}); ????ThreadPoolExecutor pool2 = MyPool.getInstance().getThreadPool(); ????pool2.execute(newRunnable() ????{ ????????@Override ????????publicvoidrun() ????????{ ????????????System.out.println("普通線程池中的線程"); ????????} ????}); ????ScheduledThreadPoolExecutor pool3 = MyPool.getInstance() ????????????.getScheduledPool(); ????pool3.scheduleAtFixedRate(newRunnable() ????{ ????????@Override ????????publicvoidrun() ????????{ ????????????System.out.println("計劃任務(wù)線程池中的線程"); ????????} ????},?0,?1000, TimeUnit.MILLISECONDS); }

?

四、計劃任務(wù)運行使用

????通過上面的樣例。也看到了計劃任務(wù)線程池的使用方式。對于計劃任務(wù),除了能夠運行普不同線程池中線程的任務(wù)以外。還能夠運行計劃任務(wù)特殊的線程要求。比方:scheduleWithFixedDelay(command, initialDelay, delay, unit);在初始化延遲之后,以特定的延遲時間反復(fù)運行。scheduleAtFixedRate(command, initialDelay, period, unit);在初始化延遲時間之后,以固定頻率反復(fù)運行。這兩種的差別是下一次運行時間延遲計算的開始時間不同,第一種是從上一次任務(wù)開始運行的時候計算。另外一種是從上一次任務(wù)運行結(jié)束的時候計算。這兩種和java之前版本號中Timer類非常相似。

可是Timer有非常多缺陷,具體的缺陷不再具體說明。而這些缺陷都能夠通過ScheduledExecutorService給完美解決。所以是時候該丟棄Timer了

?

?

?

總結(jié)

以上是生活随笔為你收集整理的java线程和线程池的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。