**版權聲明:本文為小斑馬偉原創文章,轉載請注明出處!
線程池:第四種獲取線程的方法:線程池,一個ExecutorService,它使用可能的幾個池線程之一執行每個提交的任務,通常使用Executors 工廠方法配置。
線程池可以解決兩個不同問題:由于減少了每個任務調用的開銷,它們通常可以在執行大量異步任務時提供增強的性能,并且還可以提供綁定和管理資源(包括執行任務集時使用的線程)的方法。每個ThreadPoolExecutor 還維護著一些基本的統計數據,如完成的任務數。
為了便于跨大量上下文使用,此類提供了很多可調整的參數和擴展鉤子(hook)。但是,強烈建議程序員使用較為方便的Executors 工廠方法:
?Executors.newCachedThreadPool()(無界線程池,可以進行自動線程回收)
?Executors.newFixedThreadPool(int)(固定大小線程池)
?Executors.newSingleThreadExecutor()(單個后臺線程)
它們均為大多數使用場景預定義了設置。
/*
* 一、線程池:提供了一個線程隊列,隊列中保存著所有等待狀態的線程。避免了創建與銷毀額外開銷,提高了響應的速度。
*
* 二、線程池的體系結構:
* java.util.concurrent.Executor : 負責線程的使用與調度的根接口
* |--**ExecutorService 子接口: 線程池的主要接口
* |--ThreadPoolExecutor 線程池的實現類
* |--ScheduledExecutorService 子接口:負責線程的調度
* |--ScheduledThreadPoolExecutor :繼承 ThreadPoolExecutor, 實現 ScheduledExecutorService
*
* 三、工具類 : Executors
* ExecutorService newFixedThreadPool() : 創建固定大小的線程池
* ExecutorService newCachedThreadPool() : 緩存線程池,線程池的數量不固定,可以根據需求自動的更改數量。
* ExecutorService newSingleThreadExecutor() : 創建單個線程池。線程池中只有一個線程
*
* ScheduledExecutorService newScheduledThreadPool() : 創建固定大小的線程,可以延遲或定時的執行任務。
*/
public class TestThreadPool {
public static void main(String[] args) throws Exception {
//1. 創建線程池
ExecutorService pool = Executors.newFixedThreadPool(5);
List<Future<Integer>> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Future<Integer> future = pool.submit(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
});
list.add(future);
}
pool.shutdown();
for (Future<Integer> future : list) {
System.out.println(future.get());
}
/*ThreadPoolDemo tpd = new ThreadPoolDemo();
//2. 為線程池中的線程分配任務
for (int i = 0; i < 10; i++) {
pool.submit(tpd);
}
//3. 關閉線程池
pool.shutdown();*/
}
// new Thread(tpd).start();
// new Thread(tpd).start();
}
class ThreadPoolDemo implements Runnable{
private int i = 0;
@Override
public void run() {
while(i <= 100){
System.out.println(Thread.currentThread().getName() + " : " + i++);
}
}
線程池的調度:一個ExecutorService,可安排在給定的延遲后運行或定期執行的命令。
public class TestScheduledThreadPool {
public static void main(String[] args) throws Exception {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
Future<Integer> result = pool.schedule(new Callable<Integer>(){
@Override
public Integer call() throws Exception {
int num = new Random().nextInt(100);//生成隨機數
System.out.println(Thread.currentThread().getName() + " : " + num);
return num;
}
}, 1, TimeUnit.SECONDS);
System.out.println(result.get());
}
pool.shutdown();
}
}
Fork/Join 框架:Fork/Join 框架:就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行join 匯總。
采用“工作竊取”模式(work-stealing):當執行新的任務時它可以將其拆分分成更小的任務執行,并將小任務加到線程隊列中,然后再從一個隨機線程的隊列中偷一個并把它放在自己的隊列中。
相對于一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務的處理方式上.在一般的線程池中,如果一個線程正在執行的任務由于某些原因無法繼續運行,那么該線程會處于等待狀態。而在fork/join框架實現中,如果某個子問題由于等待另外一個子問題的完成而無法繼續運行。那么處理該子問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式減少了線程的等待時間,提高了性能。
public class TestForkJoinPool {
public static void main(String[] args) {
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinSumCalculate(0L, 50000000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//166-1996-10590
}
@Test
public void test1(){
Instant start = Instant.now();
long sum = 0L;
for (long i = 0L; i <= 50000000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//35-3142-15704
}
//java8 新特性
@Test
public void test2(){
Instant start = Instant.now();
Long sum = LongStream.rangeClosed(0L, 50000000000L)
.parallel()
.reduce(0L, Long::sum);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//1536-8118
}
class ForkJoinSumCalculate extends RecursiveTask<Long>{
/**
*
*/
private static final long serialVersionUID = -259195479995561737L;
private long start;
private long end;
private static final long THURSHOLD = 10000L; //臨界值
public ForkJoinSumCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if(length <= THURSHOLD){
long sum = 0L;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
}else{
long middle = (start + end) / 2;
ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle);
left.fork(); //進行拆分,同時壓入線程隊列
ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle+1, end);
right.fork(); //
return left.join() + right.join();
}
}