推薦:Java并發程式設計彙總
Java并發程式設計一四種常用線程池簡述
我們使用線程是用來執行任務的,是以,首先我們得有一個任務,這裡我們定義線程的任務很簡單,就是輸出自己(目前線程)的
name
,為了友善觀察,在每個線程的執行邏輯中
sleep(500)
。
任務
Task
類,實作了
Runnable
接口。
package threadpool;
class Task implements Runnable {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
SingleThreadExecutor
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SingleThreadExecutor {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 1000; i++) {
executorService.execute(new Task());
}
}
}
ExecutorService
接口繼承了
Executor
接口,它比
Executor
接口有更豐富的方法,便于我們使用。
Executors
是Java線程池的工具類。
輸出:
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
上面的輸出其實隻是一部分,很顯然會輸出一千個
pool-1-thread-1
。
SingleThreadExecutor
這種線程池隻會建立一個線程去執行所有的任務。
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
corePoolSize=1
,
maximumPoolSize=1
,很明顯核心線程數和最大線程數都是
1
,這裡的
keepAliveTime=0
說明線程池不需要去試圖銷毀線程,因為
keepAliveTime
對核心線程是沒有限制的,又
corePoolSize
和
maximumPoolSize
都是
1
,即線程池的線程都是核心線程。
workQueue
是
LinkedBlockingQueue
,等以後寫阻塞隊列相關的部落格時,再詳細介紹
LinkedBlockingQueue
,現在我們隻需要知道
LinkedBlockingQueue
這種阻塞隊列,調用它的無參構造器,建立的阻塞隊列的容量是
Integer.MAX_VALUE
,你可以認為是無窮大。這也很符合
SingleThreadExecutor
的特性,這種線程池隻會建立一個線程來執行任務,而線程池建立
corePoolSize
個核心線程後,需要等待任務隊列滿了之後再去建立其他的線程來幫忙,而
SingleThreadExecutor
這種線程池的任務隊列容量無窮大(這裡認為
Integer.MAX_VALUE
為無窮大),也就無需建立核心線程以外的線程來幫忙了。
/**
* Creates a {@code LinkedBlockingQueue} with a capacity of
* {@link Integer#MAX_VALUE}.
*/
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
FixedThreadPool
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4);
for (int i = 0; i < 1000; i++) {
executorService.execute(new Task());
}
}
}
輸出:
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-1
pool-1-thread-4
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-3
pool-1-thread-2
pool-1-thread-1
pool-1-thread-4
pool-1-thread-2
pool-1-thread-4
pool-1-thread-3
上面的輸出也是輸出的一部分,這種線程池可以和
SingleThreadExecutor
進行對比了解,
SingleThreadExecutor
建立一個線程執行任務,而
FixedThreadPool
建立固定數量的線程執行任務。
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue. At any point, at most
* {@code nThreads} threads will be active processing tasks.
* If additional tasks are submitted when all threads are active,
* they will wait in the queue until a thread is available.
* If any thread terminates due to a failure during execution
* prior to shutdown, a new one will take its place if needed to
* execute subsequent tasks. The threads in the pool will exist
* until it is explicitly {@link ExecutorService#shutdown shutdown}.
*
* @param nThreads the number of threads in the pool
* @return the newly created thread pool
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
和
SingleThreadExecutor
的建立方法很相似,就不多說了。
CachedThreadPool
測試代碼:
package threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 1000; i++) {
executorService.execute(new Task());
}
}
}
輸出:
pool-1-thread-791
pool-1-thread-868
pool-1-thread-864
pool-1-thread-790
pool-1-thread-853
pool-1-thread-789
pool-1-thread-863
pool-1-thread-717
pool-1-thread-776
pool-1-thread-865
pool-1-thread-861
pool-1-thread-782
pool-1-thread-857
pool-1-thread-859
pool-1-thread-858
pool-1-thread-751
pool-1-thread-692
上面的輸出也是輸出的一部分,可見這種線程池建立線程就比較随意了。
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
SynchronousQueue
實際上不是一個真正的隊列,因為它不會為隊列中元素維護存儲空間,與其他隊列不同的是,它維護一組線程,這些線程在等待着把元素(任務)加入或移出隊列,是以可以知道,當任務來了,
SynchronousQueue
就把任務交給線程池,如果線程池沒有空閑的線程,就會建立線程去處理這個任務,這就是為什麼這種線程池建立線程看起來比較随意了,
corePoolSize=0
說明這種線程池沒有核心線程,也就是線程池可以試圖去銷毀所有閑置的線程,
maximumPoolSize=Integer.MAX_VALUE
可以認為這種線程池可以無限地建立線程(這裡認為
Integer.MAX_VALUE
為無窮大)。
圖示如下:
這裡的
keepAliveTime=60L
說明線程池會試圖銷毀線程,當線程閑置60秒(機關是秒)後就可能會被銷毀。
ScheduledThreadPool
測試代碼:
package threadpool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
threadPool.schedule(new Task(), 5, TimeUnit.SECONDS);
}
}
輸出:
pool-1-thread-1
/**
* Creates and executes a one-shot action that becomes enabled
* after the given delay.
*
* @param command the task to execute
* @param delay the time from now to delay execution
* @param unit the time unit of the delay parameter
* @return a ScheduledFuture representing pending completion of
* the task and whose {@code get()} method will return
* {@code null} upon completion
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
*/
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
delay
為
5
,機關為秒,也就是延遲
5
秒執行,并且這個調用隻會執行一次任務。
測試代碼:
package threadpool;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10);
threadPool.scheduleAtFixedRate(new Task(), 1, 1, TimeUnit.SECONDS);
}
}
輸出:
pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-4
pool-1-thread-1
pool-1-thread-5
pool-1-thread-3
輸出隻是一部分。
/**
* 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
* {@code initialDelay} then {@code initialDelay+period}, then
* {@code initialDelay + 2 * period}, and so on.
* If any execution of the task
* encounters an exception, subsequent executions are suppressed.
* Otherwise, the task will only terminate via cancellation or
* termination of the executor. If any execution of this task
* takes longer than its period, then subsequent executions
* may start late, but will not concurrently execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the task, and whose {@code get()} method will throw an
* exception upon cancellation
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
* @throws IllegalArgumentException if period less than or equal to zero
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
initialDelay=1
、
period=1
,機關為秒,也就是延遲
1
秒執行任務,并且以
1
秒為一個周期一直執行任務。
顯然這種線程池,很适合執行具有周期性的任務。
/**
* Creates a new {@code ScheduledThreadPoolExecutor} with the
* given core pool size.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @throws IllegalArgumentException if {@code corePoolSize < 0}
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}