當前位置:首頁 » 編程語言 » 創建java線程池

創建java線程池

發布時間: 2022-06-10 09:03:25

Ⅰ 如何創建並運行java線程

1
2
3
4
5
6
7
8
9
10
11

創建線程,就是這樣
extends Thread 或者 implements Runnable,但是有很多問題;

所以引申出了下面的線程池
Java通過Executors提供四種線程池,分別為:
newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,
若無可回收,則新建線程。
newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
newScheledThreadPool 創建一個定長線程池,支持定時及周期性任務執行。
newSingleThreadExecutor 創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,
保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。

Ⅱ 什麼是java線程池

多線程是為了能夠讓計算機資源合理的分配,對於處理不同的任務創建不同的線程進行處理,但是計算機創建一個線程或者銷毀一個線程所花費的也是比較昂貴的,有時候需要同時處理的事情比較多,就需要我們頻繁的進行線程的創建和銷毀,這樣花費的時間也是比較多的。為了解決這一問題,我們就可以引用線程池的概念。
所謂線程池就是將線程集中管理起來,當需要線程的時候,可以從線程池中獲取空閑的線程,這樣可以減少線程的頻繁創建與銷毀,節省很大的時間和減少很多不必要的操作。
在java中提供了ThreadPoolExecutor類來進行線程的管理,這個類繼承於AbstractExecutorService,而AbstractExecutorService實現了ExecutorService介面,我們可以使用ThreadPoolExecutor來進行線程池的創建。
在ThreadPoolExecutor的構造方法中,有多個參數,可以配置不同的參數來進行優化。這個類的源碼構造方法為:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)其中每個參數代表的意義分別為
corePoolSize : 線程池中的核心線程數量,當線程池中當前的線程數小於這個配置的時候,如果有一個新的任務到來,即使線程池中還存在空閑狀態的線程,程序也會繼續創建一個新的線程放進線程池當中
maximumPoolSize: 線程池中的線程最大數量
keepAliveTime:當線程池中的線程數量大於配置的核心線程數量(corePoolSize)的時候,如果當前有空閑的線程,則當這個空閑線程可以存在的時間,如果在keepAliveTime這個時間點內沒有新的任務使用這個線程,那麼這個線程將會結束,核心線程不會結束,但是如果配置了allowCoreThreadTimeOut = true,則當空閑時間超過keepAliveTime之後,線程也會被結束調,默認allowCoreThreadTimeOut = false,即表示默認情況下,核心線程會一直存在於線程池當中。
unit : 空閑線程保持連接時間(keepAliveTime)的時間單位
workQueue:阻塞的任務隊列,用來保存等待需要執行的任務。
threadFactory :線程工廠,可以根據自己的需求去創建線程的對象,設置線程的名稱,優先順序等屬性信息。
handler:當線程池中存在的線程數超過設置的最大值之後,新的任務就會被拒絕,可以自己定義一個拒絕的策略,當新任務被拒絕之後,就會使用hander方法進行處理。
在java中也提供了Executors工具類,在這個工具類中提供了多個創建線程池的靜態方法,其中包含newCachedThreadPool、newFixedThreadPool、newScheledThreadPool、newSingleThreadExecutor等。但是他們每個方法都是創建了ThreadPoolExecutor對象,不同的是,每個對象的初始 參數值不一樣;

Ⅲ java創建線程池有哪些

ava通過Executors提供四種線程池,分別為:
newCachedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
newFixedThreadPool
創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
newScheledThreadPool
創建一個定長線程池,支持定時及周期性任務執行。
newSingleThreadExecutor
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO,
LIFO,
優先順序)執行。

Ⅳ java常用的幾種線程池實例講解

下面給你介紹4種線程池:

1、newCachedThreadPool:

  • 底層:返回ThreadPoolExecutor實例,corePoolSize為0;maximumPoolSize為Integer.MAX_VALUE;keepAliveTime為60L;unit為TimeUnit.SECONDS;workQueue為SynchronousQueue(同步隊列)

  • 通俗:當有新任務到來,則插入到SynchronousQueue中,由於SynchronousQueue是同步隊列,因此會在池中尋找可用線程來執行,若有可以線程則執行,若沒有可用線程則創建一個線程來執行該任務;若池中線程空閑時間超過指定大小,則該線程會被銷毀。

  • 適用:執行很多短期非同步的小程序或者負載較輕的伺服器

2、newFixedThreadPool:


  • 底層:返回ThreadPoolExecutor實例,接收參數為所設定線程數量nThread,corePoolSize為nThread,maximumPoolSize為nThread;keepAliveTime為0L(不限時);unit為:TimeUnit.MILLISECONDS;WorkQueue為:new LinkedBlockingQueue<Runnable>()無解阻塞隊列

  • 通俗:創建可容納固定數量線程的池子,每隔線程的存活時間是無限的,當池子滿了就不在添加線程了;如果池中的所有線程均在繁忙狀態,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

  • 適用:執行長期的任務,性能好很多

3、newSingleThreadExecutor

  • 底層:包裝的ThreadPoolExecutor實例,corePoolSize為1;maximumPoolSize為1;keepAliveTime為0L;unit為:TimeUnit.MILLISECONDS;workQueue為:new LinkedBlockingQueue<Runnable>()無解阻塞隊列

  • 通俗:創建只有一個線程的線程池,且線程的存活時間是無限的;當該線程正繁忙時,對於新任務會進入阻塞隊列中(無界的阻塞隊列)

  • 適用:一個任務一個任務執行的場景

4、NewScheledThreadPool:

  • 底層:創建ScheledThreadPoolExecutor實例,corePoolSize為傳遞來的參數,maximumPoolSize為Integer.MAX_VALUE;keepAliveTime為0;unit為:TimeUnit.NANOSECONDS;workQueue為:new DelayedWorkQueue()一個按超時時間升序排序的隊列

  • 通俗:創建一個固定大小的線程池,線程池內線程存活時間無限制,線程池可以支持定時及周期性任務執行,如果所有線程均處於繁忙狀態,對於新任務會進入DelayedWorkQueue隊列中,這是一種按照超時時間排序的隊列結構

  • 適用:周期性執行任務的場景

最後給你說一下線程池任務執行流程:

  • 當線程池小於corePoolSize時,新提交任務將創建一個新線程執行任務,即使此時線程池中存在空閑線程。

  • 當線程池達到corePoolSize時,新提交任務將被放入workQueue中,等待線程池中任務調度執行

  • 當workQueue已滿,且maximumPoolSize>corePoolSize時,新提交任務會創建新線程執行任務

  • 當提交任務數超過maximumPoolSize時,新提交任務由RejectedExecutionHandler處理

  • 當線程池中超過corePoolSize線程,空閑時間達到keepAliveTime時,關閉空閑線程

  • 當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閑時間達到keepAliveTime也將關閉

Ⅳ java線程池怎麼實現

要想理解清楚java線程池實現原理,明白下面幾個問題就可以了:

(1):線程池存在哪些狀態,這些狀態之間是如何進行切換的呢?

(2):線程池的種類有哪些?

(3):創建線程池需要哪些參數,這些參數的具體含義是什麼?

(4):將任務添加到線程池之後運行流程?

(5):線程池是怎麼做到重用線程的呢?

(6):線程池的關閉

首先回答第一個問題:線程池存在哪些狀態;

查看ThreadPoolExecutor源碼便知曉:

[java]view plain

  • //runStateisstoredinthehigh-orderbits

  • privatestaticfinalintRUNNING=-1<<COUNT_BITS;

  • privatestaticfinalintSHUTDOWN=0<<COUNT_BITS;

  • privatestaticfinalintSTOP=1<<COUNT_BITS;

  • privatestaticfinalintTIDYING=2<<COUNT_BITS;

  • =3<<COUNT_BITS;

  • 存在5種狀態:

    <1>Running:可以接受新任務,同時也可以處理阻塞隊列裡面的任務;

    <2>Shutdown:不可以接受新任務,但是可以處理阻塞隊列裡面的任務;

    <3>Stop:不可以接受新任務,也不處理阻塞隊列裡面的任務,同時還中斷正在處理的任務;

    <4>Tidying:屬於過渡階段,在這個階段表示所有的任務已經執行結束了,當前線程池中是不存在有效的線程的,並且將要調用terminated方法;

    <5>Terminated:終止狀態,這個狀態是在調用完terminated方法之後所處的狀態;

    那麼這5種狀態之間是如何進行轉換的呢?查看ThreadPoolExecutor源碼裡面的注釋便可以知道啦:

    [java]view plain

  • *RUNNING->SHUTDOWN

  • *Oninvocationofshutdown(),perhapsimplicitlyinfinalize()

  • *(RUNNINGorSHUTDOWN)->STOP

  • *OninvocationofshutdownNow()

  • *SHUTDOWN->TIDYING

  • *Whenbothqueueandpoolareempty

  • *STOP->TIDYING

  • *Whenpoolisempty

  • *TIDYING->TERMINATED

  • *Whentheterminated()hookmethodhascompleted

  • 從上面可以看到,在調用shutdown方法的時候,線程池狀態會從Running轉換成Shutdown;在調用shutdownNow方法的時候,線程池狀態會從Running/Shutdown轉換成Stop;在阻塞隊列為空同時線程池為空的情況下,線程池狀態會從Shutdown轉換成Tidying;在線程池為空的情況下,線程池狀態會從Stop轉換成Tidying;當調用terminated方法之後,線程池狀態會從Tidying轉換成Terminate;

    在明白了線程池的各個狀態以及狀態之間是怎麼進行切換之後,我們來看看第二個問題,線程池的種類:

    (1):CachedThreadPool:緩存線程池,該類線程池中線程的數量是不確定的,理論上可以達到Integer.MAX_VALUE個,這種線程池中的線程都是非核心線程,既然是非核心線程,那麼就存在超時淘汰機制了,當裡面的某個線程空閑時間超過了設定的超時時間的話,就會回收掉該線程;

    (2):FixedThreadPool:固定線程池,這類線程池中是只存在核心線程的,對於核心線程來說,如果我們不設置allowCoreThreadTimeOut屬性的話是不存在超時淘汰機制的,這類線程池中的corePoolSize的大小是等於maximumPoolSize大小的,也就是說,如果線程池中的線程都處於活動狀態的話,如果有新任務到來,他是不會開辟新的工作線程來處理這些任務的,只能將這些任務放到阻塞隊列裡面進行等到,直到有核心線程空閑為止;

    (3):ScheledThreadPool:任務線程池,這種線程池中核心線程的數量是固定的,而對於非核心線程的數量是不限制的,同時對於非核心線程是存在超時淘汰機制的,主要適用於執行定時任務或者周期性任務的場景;

    (4):SingleThreadPool:單一線程池,線程池裡面只有一個線程,同時也不存在非核心線程,感覺像是FixedThreadPool的特殊版本,他主要用於確保任務在同一線程中的順序執行,有點類似於進行同步吧;

    接下來我們來看第三個問題,創建線程池需要哪些參數:

    同樣查看ThreadPoolExecutor源碼,查看創建線程池的構造函數:

    [java]view plain

  • publicThreadPoolExecutor(intcorePoolSize,

  • intmaximumPoolSize,

  • longkeepAliveTime,

  • TimeUnitunit,

  • BlockingQueue<Runnable>workQueue,

  • ThreadFactorythreadFactory,

  • )

  • 不管你調用的是ThreadPoolExecutor的哪個構造函數,最終都會執行到這個構造函數的,這個構造函數有7個參數,正是由於對這7個參數值的賦值不同,造成生成不同類型的線程池,比如我們常見的CachedThreadPoolExecutor、FixedThreadPoolExecutor

    SingleThreadPoolExecutor、ScheledThreadPoolExecutor,我們老看看這幾個參數的具體含義:

    <1>corePoolSize:線程池中核心線程的數量;當提交一個任務到線程池的時候,線程池會創建一個線程來執行執行任務,即使有其他空閑的線程存在,直到線程數達到corePoolSize時不再創建,這時候會把提交的新任務放入到阻塞隊列中,如果調用了線程池的preStartAllCoreThreads方法,則會在創建線程池的時候初始化出來核心線程;

    <2>maximumPoolSize:線程池允許創建的最大線程數;如果阻塞隊列已經滿了,同時已經創建的線程數小於最大線程數的話,那麼會創建新的線程來處理阻塞隊列中的任務;

    <3>keepAliveTime:線程活動保持時間,指的是工作線程空閑之後繼續存活的時間,默認情況下,這個參數只有線程數大於corePoolSize的時候才會起作用,即當線程池中的線程數目大於corePoolSize的時候,如果某一個線程的空閑時間達到keepAliveTime,那麼這個線程是會被終止的,直到線程池中的線程數目不大於corePoolSize;如果調用allowCoreThreadTimeOut的話,在線程池中線程數量不大於corePoolSize的時候,keepAliveTime參數也可以起作用的,知道線程數目為0為止;

    <4>unit:參數keepAliveTime的時間單位;

    <5>workQueue:阻塞隊列;用於存儲等待執行的任務,有四種阻塞隊列類型,ArrayBlockingQueue(基於數組的有界阻塞隊列)、LinkedBlockingQueue(基於鏈表結構的阻塞隊列)、SynchronousQueue(不存儲元素的阻塞隊列)、PriorityBlockingQueue(具有優先順序的阻塞隊列);

    <6>threadFactory:用於創建線程的線程工廠;

    <7>handler:當阻塞隊列滿了,且沒有空閑線程的情況下,也就是說這個時候,線程池中的線程數目已經達到了最大線程數量,處於飽和狀態,那麼必須採取一種策略來處理新提交的任務,我們可以自己定義處理策略,也可以使用系統已經提供給我們的策略,先來看看系統為我們提供的4種策略,AbortPolicy(直接拋出異常)、CallerRunsPolicy(只有調用者所在的線程來運行任務)、DiscardOldestPolicy(丟棄阻塞隊列中最近的一個任務,並執行當前任務)、Discard(直接丟棄);

    接下來就是將任務添加到線程池之後的運行流程了;

    我們可以調用submit或者execute方法,兩者最大的區別在於,調用submit方法的話,我們可以傳入一個實現Callable介面的對象,進而能在當前任務執行結束之後通過Future對象獲得任務的返回值,submit內部實際上還是執行的execute方法;而調用execute方法的話,是不能獲得任務執行結束之後的返回值的;此外,調用submit方法的話是可以拋出異常的,但是調用execute方法的話,異常在其內部得到了消化,也就是說異常在其內部得到了處理,不會向外傳遞的;

    因為submit方法最終也是會執行execute方法的,因此我們只需要了解execute方法就可以了:

    在execute方法內部會分三種情況來進行處理:

    <1>:首先判斷當前線程池中的線程數量是否小於corePoolSize,如果小於的話,則直接通過addWorker方法創建一個新的Worker對象來執行我們當前的任務;

    <2>:如果說當前線程池中的線程數量大於corePoolSize的話,那麼會嘗試將當前任務添加到阻塞隊列中,然後第二次檢查線程池的狀態,如果線程池不在Running狀態的話,會將剛剛添加到阻塞隊列中的任務移出,同時拒絕當前任務請求;如果第二次檢查發現當前線程池處於Running狀態的話,那麼會查看當前線程池中的工作線程數量是否為0,如果為0的話,就會通過addWorker方法創建一個Worker對象出來處理阻塞隊列中的任務;

    <3>:如果原先線程池就不處於Running狀態或者我們剛剛將當前任務添加到阻塞隊列的時候出現錯誤的話,那麼會去嘗試通過addWorker創建新的Worker來處理當前任務,如果添加失敗的話,則拒絕當前任務請求;

    可以看到在上面的execute方法中,我們僅僅只是檢查了當前線程池中的線程數量有沒有超過corePoolSize的情況,那麼當前線程池中的線程數量有沒有超過maximumPoolSize是在哪裡檢測的呢?實際上是在addWorker方法裡面了,我們可以看下addWorker裡面的一段代碼:

    [java]view plain

  • if(wc>=CAPACITY||

  • wc>=(core?corePoolSize:maximumPoolSize))

  • returnfalse;

  • 如果當前線程數量超過maximumPoolSize的話,直接就會調用return方法,返回false;

    其實到這里我們很明顯可以知道,一個線程池中線程的數量實際上就是這個線程池中Worker的數量,如果Worker的大小超過了corePoolSize,那麼任務都在阻塞隊列裡面了,Worker是Java對我們任務的一個封裝類,他的聲明是醬紫的:

    [java]view plain

  • privatefinalclassWorker

  • implementsRunnable

  • 可以看到他實現了Runnable介面,他是在addWorker方法裡面通過new Worker(firstTask)創建的,我們來看看他的構造函數就知道了:

    [java]view plain

  • Worker(RunnablefirstTask){

  • setState(-1);//

  • this.firstTask=firstTask;

  • this.thread=getThreadFactory().newThread(this);

  • }

  • 而這里的firstTask其實就是我們調用execute或者submit的時候傳入的那個參數罷了,一般來說這些參數是實現Callable或者Runnable介面的;

    在通過addWorker方法創建出來Worker對象之後,這個方法的最後會執行Worker內部thread屬性的start方法,而這個thread屬性實際上就是封裝了Worker的Thread,執行他的start方法實際上執行的是Worker的run方法,因為Worker是實現了Runnable介面的,在run方法裡面就會執行runWorker方法,而runWorker方法裡面首先會判斷當前我們傳入的任務是否為空,不為空的話直接就會執行我們通過execute或者submit方法提交的任務啦,注意一點就是我們雖然會通過submit方法提交實現了Callable介面的對象,但是在調用submit方法的時候,其實是會將Callable對象封裝成實現了Runnable介面對象的,不信我們看看submit方法源碼是怎麼實現的:

    [java]view plain

  • public<T>Future<T>submit(Callable<T>task){

  • if(task==null)thrownewNullPointerException();

  • RunnableFuture<T>ftask=newTaskFor(task);

  • execute(ftask);

  • returnftask;

  • }

  • 看到沒有呢,實際上在你傳入實現了Callable介面對象的時候,在submit方法裡面是會將其封裝成RunnableFuture對象的,而RunnableFuture介面是繼承了Runnable介面的;那麼說白了其實就是直接執行我們提交任務的run方法了;如果為空的話,則會通過getTask方法從阻塞隊列裡面拿出一個任務去執行;在任務執行結束之後繼續從阻塞隊列裡面拿任務,直到getTask的返回值為空則退出runWorker內部循環,那麼什麼情況下getTask返回為空呢?查看getTask方法的源碼注釋可以知道:在Worker必須需要退出的情況下getTask會返回空,具體什麼情況下Worker會退出呢?(1):當Worker的數量超過maximumPoolSize的時候;(2):當線程池狀態為Stop的時候;(3):當線程池狀態為Shutdown並且阻塞隊列為空的時候;(4):使用等待超時時間從阻塞隊列中拿數據,但是超時之後仍然沒有拿到數據;

    如果runWorker方法退出了它裡面的循環,那麼就說明當前阻塞隊列裡面是沒有任務可以執行的了,你可以看到在runWorker方法內部的finally語句塊中執行了processWorkerExit方法,用來對Worker對象進行回收操作,這個方法會傳入一個參數表示需要刪除的Worker對象;在進行Worker回收的時候會調用tryTerminate方法來嘗試關閉線程池,在tryTerminate方法裡面會檢查是否有Worker在工作,檢查線程池的狀態,沒問題的話就會將當前線程池的狀態過渡到Tidying,之後調用terminated方法,將線程池狀態更新到Terminated;

    從上面的分析中,我們可以看出線程池運行的4個階段:

    (1):poolSize < corePoolSize,則直接創建新的線程(核心線程)來執行當前提交的任務;

    (2):poolSize = corePoolSize,並且此時阻塞隊列沒有滿,那麼會將當前任務添加到阻塞隊列中,如果此時存在工作線程(非核心線程)的話,那麼會由工作線程來處理該阻塞隊列中的任務,如果此時工作線程數量為0的話,那麼會創建一個工作線程(非核心線程)出來;

    (3):poolSize = corePoolSize,並且此時阻塞隊列已經滿了,那麼會直接創建新的工作線程(非核心線程)來處理阻塞隊列中的任務;

    (4):poolSize = maximumPoolSize,並且此時阻塞隊列也滿了的話,那麼會觸發拒絕機制,具體決絕策略採用的是什麼就要看我們創建ThreadPoolExecutor的時候傳入的RejectExecutionHandler參數了;

    接下來就是線程池是怎麼做到重用線程的呢?

    個人認為線程池裡面重用線程的工作是在getTask裡面實現的,在getTask裡面是存在兩個for死循環嵌套的,他會不斷的從阻塞對列裡面取出需要執行的任務,返回給我們的runWorker方法裡面,而在runWorker方法裡面只要getTask返回的任務不是空就會執行該任務的run方法來處理它,這樣一直執行下去,直到getTask返回空為止,此時的情況就是阻塞隊列裡面沒有任務了,這樣一個線程處理完一個任務之後接著再處理阻塞隊列中的另一個任務,當然在線程池中的不同線程是可以並發處理阻塞隊列中的任務的,最後在阻塞隊列內部不存在任務的時候會去判斷是否需要回收Worker對象,其實Worker對象的個數就是線程池中線程的個數,至於什麼情況才需要回收,上面已經說了,就是四種情況了;

    最後就是線程池是怎樣被關閉的呢?

    涉及到線程池的關閉,需要用到兩個方法,shutdown和shutdownNow,他們都是位於ThreadPoolExecutor裡面的,對於shutdown的話,他會將線程池狀態切換成Shutdown,此時是不會影響對阻塞隊列中任務執行的,但是會拒絕執行新加進來的任務,同時會回收閑置的Worker;而shutdownNow方法會將線程池狀態切換成Stop,此時既不會再去處理阻塞隊列裡面的任務,也不會去處理新加進來的任務,同時會回收所有Worker;

Ⅵ java for循環中創建線程池

  1. 首先要明確線程池的意思,就是線程預先創建好放在一個池裡面,使用後不會銷毀

  2. 要區分任務和線程池,任務可以不斷添加,但是線程池裡線程的個數是固定的,當任務數超過線程數後,後面的任務需要等待有空閑的線程才會執行

  3. 所以不斷添加任務沒有關系,如果池中有50個線程,你添加100個任務同一時間也只會執行50個任務,剩下的50個任務需要等待前面的任務執行完畢後繼續執行

  4. 所以你的主線程原則上可以不斷for,但是你總得有個結束點吧

Ⅶ 如何創建Java中的線程池

ThreadPoolExecutor executor = new ThreadPoolExecutor(2,3,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(5));

Ⅷ 創建線程有幾種方式和Java中常用的線程池

java創建線程的方式有三種
第一種是繼承Thread類 實現方法run() 不可以拋異常 無返回值
第二種是實現Runnable介面 實現方法run() 不可以拋異常 無返回值
第三種是實現Callable<T>介面,介面中要覆蓋的方法是 public <T> call() 注意:此方法可以拋異常,而前兩種不能 而且此方法可以有返回值

第三種如何運行呢 Callable介面在util.concurrent包中,由線程池提交
import java.util.concurrent.*;
ExecutorService e = Executors.newFixedThreadPool(10); 參數表示最多可以運行幾個線程
e.submit(); 這個裡面參數傳 實現Callable介面那個類的對象

Ⅸ 如何創建並運行Java線程

Java線程類也是一個object類,它的實例都繼承自java.lang.Thread或其子類。 可以用如下方式用java中創建一個線程:

Tread thread = new Thread();

執行該線程可以調用該線程的start()方法:

thread.start();

在上面的例子中,我們並沒有為線程編寫運行代碼,因此調用該方法後線程就終止了。

編寫線程運行時執行的代碼有兩種方式:一種是創建Thread子類的一個實例並重寫run方法,第二種是創建類的時候實現Runnable介面。接下來我們會具體講解這兩種方法:

創建Thread的子類

創建Thread子類的一個實例並重寫run方法,run方法會在調用start()方法之後被執行。例子如下:

public class MyThread extends Thread {
public void run(){
System.out.println("MyThread running");
}
}

可以用如下方式創建並運行上述Thread子類

MyThread myThread = new MyThread();
myTread.start();

一旦線程啟動後start方法就會立即返回,而不會等待到run方法執行完畢才返回。就好像run方法是在另外一個cpu上執行一樣。當run方法執行後,將會列印出字元串MyThread running。

你也可以如下創建一個Thread的匿名子類:

Thread thread = new Thread(){
public void run(){
System.out.println("Thread Running");
}
};
thread.start();

當新的線程的run方法執行以後,計算機將會列印出字元串」Thread Running」。

實現Runnable介面

第二種編寫線程執行代碼的方式是新建一個實現了java.lang.Runnable介面的類的實例,實例中的方法可以被線程調用。下面給出例子:

public class MyRunnable implements Runnable {
public void run(){
System.out.println("MyRunnable running");
}
}

為了使線程能夠執行run()方法,需要在Thread類的構造函數中傳入 MyRunnable的實例對象。示例如下:

Thread thread = new Thread(new MyRunnable());
thread.start();

當線程運行時,它將會調用實現了Runnable介面的run方法。上例中將會列印出」MyRunnable running」。

同樣,也可以創建一個實現了Runnable介面的匿名類,如下所示:

Runnable myRunnable = new Runnable(){
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();

創建子類還是實現Runnable介面?

對於這兩種方式哪種好並沒有一個確定的答案,它們都能滿足要求。就我個人意見,我更傾向於實現Runnable介面這種方法。因為線程池可以有效的管理實現了Runnable介面的線程,如果線程池滿了,新的線程就會排隊等候執行,直到線程池空閑出來為止。而如果線程是通過實現Thread子類實現的,這將會復雜一些。

有時我們要同時融合實現Runnable介面和Thread子類兩種方式。例如,實現了Thread子類的實例可以執行多個實現了Runnable介面的線程。一個典型的應用就是線程池。

常見錯誤:調用run()方法而非start()方法

創建並運行一個線程所犯的常見錯誤是調用線程的run()方法而非start()方法,如下所示:

Thread newThread = new Thread(MyRunnable());
newThread.run(); //should be start();

起初你並不會感覺到有什麼不妥,因為run()方法的確如你所願的被調用了。但是,事實上,run()方法並非是由剛創建的新線程所執行的,而是被創建新線程的當前線程所執行了。也就是被執行上面兩行代碼的線程所執行的。想要讓創建的新線程執行run()方法,必須調用新線程的start方法。

線程名

當創建一個線程的時候,可以給線程起一個名字。它有助於我們區分不同的線程。例如:如果有多個線程寫入System.out,我們就能夠通過線程名容易的找出是哪個線程正在輸出。例子如下:

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable, "New Thread");
thread.start();
System.out.println(thread.getName());

需要注意的是,因為MyRunnable並非Thread的子類,所以MyRunnable類並沒有getName()方法。可以通過以下方式得到當前線程的引用:

Thread.currentThread();

因此,通過如下代碼可以得到當前線程的名字:

String threadName = Thread.currentThread().getName();

線程代碼舉例:

這里是一個小小的例子。首先輸出執行main()方法線程名字。這個線程JVM分配的。然後開啟10個線程,命名為1~10。每個線程輸出自己的名字後就退出。

public class ThreadExample {
public static void main(String[] args){
System.out.println(Thread.currentThread().getName());
for(int i=0; i<10; i++){
new Thread("" + i){
public void run(){
System.out.println("Thread: " + getName() + "running");
}
}.start();
}
}
}

需要注意的是,盡管啟動線程的順序是有序的,但是執行的順序並非是有序的。也就是說,1號線程並不一定是第一個將自己名字輸出到控制台的線程。這是因為線程是並行執行而非順序的。Jvm和操作系統一起決定了線程的執行順序,他和線程的啟動順序並非一定是一致的。

Ⅹ 【Java基礎】線程池的原理是什麼

什麼是線程池?

總歸為:池化技術 ---》資料庫連接池 緩存架構 緩存池 線程池 內存池,連接池,這種思想演變成緩存架構技術---> JDK設計思想有千絲萬縷的聯系

首先我們從最核心的ThreadPoolExecutor類中的方法講起,然後再講述它的實現原理,接著給出了它的使用示例,最後討論了一下如何合理配置線程池的大小。

Java 中的 ThreadPoolExecutor 類

java.uitl.concurrent.ThreadPoolExecutor 類是線程池中最核心的一個類,因此如果要透徹地了解Java 中的線程池,必須先了解這個類。下面我們來看一下 ThreadPoolExecutor 類的具體實現源碼。

在 ThreadPoolExecutor 類中提供了四個構造方法:

熱點內容
節目腳本是什麼 發布:2025-02-08 02:08:54 瀏覽:139
android的自定義屬性 發布:2025-02-08 02:07:27 瀏覽:605
怎麼看電腦的用戶名和密碼 發布:2025-02-08 02:02:48 瀏覽:796
vb動態資料庫 發布:2025-02-08 02:01:53 瀏覽:110
一台存儲可以配幾個擴展櫃 發布:2025-02-08 01:53:22 瀏覽:566
分布式存儲技術優缺點 發布:2025-02-08 01:51:37 瀏覽:245
linuxsuse重啟 發布:2025-02-08 01:49:27 瀏覽:412
java對稱加密 發布:2025-02-08 01:48:04 瀏覽:523
java報表框架 發布:2025-02-08 01:47:59 瀏覽:930
方舟手游怎麼防止踢出伺服器 發布:2025-02-08 01:42:44 瀏覽:690