摘要:類重點是那個病毒掃描程序的例子,認真看三遍。會從線程池中選擇線程,并將對象提交給線程任務。比如病毒掃描,你可以使用類實現的執行器服務,每小時運行一次病毒掃描。該應用是以固定頻率執行的病毒掃描程序。
Executors類
重點是那個病毒掃描程序的例子,認真看三遍。本文花了四個小時。
GitHub代碼歡迎star。
小白認為學習語言最好的方式就是模仿、思考別人為什么這么寫。結合栗子效果更好,也能記住知識點。
Executors類允許創建線程池并返回ExecutorService對象,執行器提供了將任務提交與對任務進行解耦的標準方法,除了對基本的線程生命周期提供支持外,窒息功能其還提供統計收集,應用管理及監控方面的功能。這一切都基于 生產者-消費者模式。 使用這種設計模式可以對大型并發應用程序很好的進行擴展。
使用這種服務對象,可以運行Runnable和Callable類的實力,你只需要做的是提交任務給服務對象就可以。ExecutorService會從線程池中選擇線程,并將Runnable對象提交給線程任務。當任務結束時,線程并不會銷毀 ,而是返回到線程池中繼續執行后續的其他任務,這樣可以 避免創建和銷毀線程帶來的額外開銷
Executors類有許多靜態方法可用來創建線程池:1、newFixedTHreadPool方法能夠創建固定大小的線程池。線程池中的線程將被用來處理任務請求,如果線程處于空閑狀態,線程不會銷毀,而是會被存放線程池中一段不確定的是將
2、newCachedThreadPool,使用該方法創建的線程池中的線程會在空閑60秒之后自動銷毀,
3、newSingleThreadExecutor該方法僅創建一個線程,當任務結束后不會銷毀而是用于處理其他任務。對于多個任務同時請求,則使用隊列來維護所有待處理的請求。隨后會順序執行。
4、newScheduledThreadPool可以把它看作是java.util.Timer的替代品,該方法創建固定大小的線程池用來調度執行任務,并返回一個ScheduledExecutorService對象,該對象提供了若干個方法用于執行任務的調度執行。
創建線程池以進行任務調度有時創建可在一定時間延遲后執行的線程,可以設置一個報警器在一段時間過后報警。在某些情況下,你也希望以 一定的頻率或固定時間間隔反復執行線程。
比如病毒掃描,你可以使用newScheduledThreadPool類實現的執行器服務,每24小時運行一次病毒掃描。如果有多個磁盤或大容量的磁盤需要掃描,將掃描的任務分解為多個單元。讓每個單元掃描某個特定的磁盤。
另一凸顯此服務很實用的應用場景是新聞聚合器。聚合器從多個新聞源收集最新新聞,并將它們排列在客戶端以供閱讀,多個數據源獲取可以并發執行,而這根據目標數據源的網絡狀況,花費的時間會不一樣??蛻舳撕蛿祿吹耐綍芷谛缘貓绦?。如果這樣的同步操作頻率很高,新的同步操作和當前正在執行的操作就有可能出現重疊。在這種情況下,最好給每次任務的執行設固定的時間間隔,ScheduledExecutosService可以幫你實現這樣的需求。
ScheduledExecutorService類1、ScheduledExecutorService 類提供了名為schedule的方法用于設定任務的未來執行。schedule方法有兩個重載版本:
//Creates and executes a ScheduledFuture that becomes enabled after the given delay.ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) //Creates and executes a one-shot action that becomes enabled after the given delay. ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit)
schedule方法接收三個參數:Callable和Runnable接口、延遲時間以及時間單位。該方法安排由 Callable和Runnable指定的任務在給定的延遲時間后執行。時間單位 由該方法的第三個參數指定。方法會返回一個Future對象給調用方。
2、除了這個簡單的延遲執行之外,ScheduledExecutorService類還提供了scheduleAtFixedRate方法,該任務可以指定任務按照一定的頻率執行。
//Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; //that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on. ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
第一次執行發生在給定的延遲之后,后續執行發生在“延遲+固定時間”,“延遲+2*固定周期”,依次類推,這種方法可以用于病毒掃描
3、scheduleWithFiedDelay方法在給定延遲之后第一次執行任務。之后按照固定好的時間間隔執行,時間間隔遞歸你以為本次任務運行到下一次任務的開始。這類調度可以用于新聞聚合應用。
//Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. ScheduledFuture> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)任務的調度執行(重點在匿名線程)
/** * Created by guo on 2018/2/16. * 演示任務調度執行 * 需求: * 如何讓任務以一定的頻率執行。 * 1、該應用是以固定頻率執行的病毒掃描程序。 * 2、當掃描開始時,程序彈出窗口以顯示掃描進度,當磁盤上所有文件被掃描之后,任務會停止。 * 3、每次掃描都需要不同的時間,通過讓線程隨機睡眠一段時間來模擬這個過程。 * 4、掃描結束之后,狀態窗口會被關閉,知道下次掃描才會彈出, */ public class VirusScanner { private static JFrame appFrame; private static JLabel statusString; private int scanNumber = 0; //1、調用Executors類的newScheduledThreadPool方法來創建線程池。 private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); private static final GregorianCalendar calendar = new GregorianCalendar(); private static VirusScanner app = new VirusScanner(); /** * scanDisk方法執行實際的掃描工作 */ public void scanDisk() { //2、使用線程池中的線程來解決多重并發掃描。 final Runnable scanner = new Runnable() { @Override public void run() { try { //將狀態窗口顯示給用戶 appFrame.setVisible(true); scanNumber++; Calendar cal = Calendar.getInstance(); //顯示掃描數以及掃描開始時間,接下來,讓當前線程隨機睡一段時間。 DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.MEDIUM); statusString.setText(" Scan" + scanNumber + " started at" + df.format(cal.getTime())); //常數1000是用來確保窗口至少顯示1秒。在實際程序中,病毒掃描代碼會放在sleep語句所在的位置。 //讓線程休眠是假裝病毒掃描持續一段時間, //當線程從休眠中喚醒時,我們隱藏了窗口,這讓用戶感覺當前一輪已經結束。 //題外話1:請卸載國產360,QQ管家,小白可以無視。需要的組件可以下載綠色版。(明明是一個開源軟件,你卻說那高危險。明明是https://www.github.com開頭。) //題外話2:感謝 架構@奇虎360,@江湖人稱小白哥。謝謝你的心意,能力沒到那,你還不能成為我職業生涯的第一位貴人。騷年,加油吧,越努力,越幸運。 Thread.sleep(1000 + new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); } } }; //重點:3、使用之前創建的調度器來讓掃描程序以固定頻率執行。 // a、掃描任務在最初的一秒延遲之后會以每隔15秒的頻率運行 // b、調用器會返回一個Future對象,用于之后取消掃描任務。 // c、為了能夠進行取消操作,創建另一個匿名線程。 // d、以下代碼所有時間單位為秒,目前只是模擬的效果。 // e、在實際應用中,病毒掃描應當每天或每幾小時執行一次 final ScheduledFuture> scanManager = scheduler.scheduleAtFixedRate(scanner, 1, 15, TimeUnit.SECONDS); /** * 匿名線程 * 這個線程只在60秒延遲之后運行一次,模擬會以一分鐘的總時間周期執行 * 每隔15秒,病毒掃描狀態窗口會彈出,并且顯示請留1秒,或更長時間。 */ scheduler.schedule(new Runnable() { @Override public void run() { //4、取消病毒掃描任務,并關閉調度器和狀態窗口 scanManager.cancel(true); scheduler.shutdown(); appFrame.dispose(); } }, 60, TimeUnit.SECONDS); } }主函數(不是重點)
/** * 不是重點的main方法: * 創建狀態窗口、設置并調用scanDisk方法。 * 注意:主線程會在之后立刻結束,而在scanDisk方法中創建的線程會在接下來一分鐘內繼續運行。 */ public static void main(String[] args) { appFrame = new JFrame(); Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize(); appFrame.setSize(400, 70); appFrame.setLocation(dimension.width / 2 - appFrame.getWidth() / 2, dimension.height / 2 - appFrame.getHeight() / 2); statusString = new JLabel(); appFrame.add(statusString); appFrame.setVisible(false); app.scanDisk(); }獲取首個已結束的運行結果
之前已經學了如何將任務提交給執行器立即執行、延遲以及周期性的運行 (計算年銷售額) 還了解到執行器可以提供并維護多個線程并發的執行任務 (模擬可取消任務的股票交易處理程序) 。在某些情況下,當提交多個任務給執行器,你可能希望處理任意以結束任務的結果,而不像等到每個任務都執行結束。目前只用過執行器的get方法會等待任務結束。當任務提交時,可以創建循環來獲取每個計算結果,代碼如下:
for(Futureresult : results) { result.get(); }
這樣就可以順序的獲取結果,但如果某個特定的任務需要長時間才能結束,那么當前的get調用會一直阻塞.在這種情況下,即使其他任務已經提前完成,也無法獲取結果,為了解決這個問題,可以使用ExecutorCompletionService類,該類會檢測提交給執行器的任務,通過take方法,可以一個個地獲取到任務執行的結果。
待續...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/68491.html
摘要:有三種狀態運行關閉終止。類類,提供了一系列工廠方法用于創建線程池,返回的線程池都實現了接口。線程池的大小一旦達到最大值就會保持不變,在提交新任務,任務將會進入等待隊列中等待。此線程池支持定時以及周期性執行任務的需求。 這是java高并發系列第19篇文章。 本文主要內容 介紹Executor框架相關內容 介紹Executor 介紹ExecutorService 介紹線程池ThreadP...
摘要:在這個示例中我們使用了一個單線程線程池的。在延遲消逝后,任務將會并發執行。這是并發系列教程的第一部分。第一部分線程和執行器第二部分同步和鎖第三部分原子操作和 Java 8 并發教程:線程和執行器 原文:Java 8 Concurrency Tutorial: Threads and Executors 譯者:BlankKelly 來源:Java8并發教程:Threads和Execut...
摘要:線程的啟動與銷毀都與本地線程同步。操作系統會調度所有線程并將它們分配給可用的??蚣艿某蓡T主要成員線程池接口接口接口以及工具類。創建單個線程的接口與其實現類用于表示異步計算的結果。參考書籍并發編程的藝術方騰飛魏鵬程曉明著 在java中,直接使用線程來異步的執行任務,線程的每次創建與銷毀需要一定的計算機資源開銷。每個任務創建一個線程的話,當任務數量多的時候,則對應的創建銷毀開銷會消耗大量...
摘要:是一個中的工具類提供工廠方法來創建不同類型的線程池從上圖中也可以看出的創建線程池的方法創建出來的線程池都實現了接口常用方法有以下幾個創建固定數目線程的線程池超出的線程會在隊列中等待創建一個可緩存線程池如果線程池長度超過處理需要可靈活回收空閑 Executors Executors 是一個Java中的工具類. 提供工廠方法來創建不同類型的線程池. showImg(https://segm...
摘要:能夠異步的執行任務,并且通常管理一個線程池。這樣我們就不用手動的去創建線程了,線程池中的所有線程都將被重用。在之后不能再提交任務到線程池。它不使用固定大小的線程池,默認情況下是主機的可用內核數。 原文地址: Java 8 Concurrency Tutorial: Threads and Executors Java 5 初次引入了Concurrency API,并在隨后的發布版本中...
閱讀 2491·2021-11-24 09:39
閱讀 3415·2021-11-15 11:37
閱讀 2268·2021-10-08 10:04
閱讀 3977·2021-09-09 11:54
閱讀 1890·2021-08-18 10:24
閱讀 1060·2019-08-30 11:02
閱讀 1805·2019-08-29 18:45
閱讀 1661·2019-08-29 16:33