欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文弄懂Java中ThreadPoolExecutor

 更新時(shí)間:2023年08月21日 09:57:22   作者:趕路人兒  
ThreadPoolExecutor是Java中的一個(gè)線程池實(shí)現(xiàn),它可以管理和控制多個(gè) Worker Threads,本文就詳細(xì)的介紹一下Java中ThreadPoolExecutor,具有一定的參考價(jià)值,感興趣的可以了解一下

一、ThreadPoolExecutor類講解

1、線程池狀態(tài):

五種狀態(tài):

線程池 的狀態(tài)

說明

RUNNING

允許提交并處理任務(wù)

SHUTDOWN

不允許提交新的任務(wù),但是會(huì)處理完已提交的任務(wù)

STOP

不允許提交新的任務(wù),也不會(huì)處理阻塞隊(duì)列中未執(zhí)行的任務(wù),

并設(shè)置正在執(zhí)行的線程的中斷標(biāo)志位

TIDYING

所有任務(wù)執(zhí)行完畢,池中工作的線程數(shù)為0,等待執(zhí)行terminated()勾子方法

TERMINATED

terminated()勾子方法執(zhí)行完畢

  • 線程池的shutdown() 方法,將線程池由 RUNNING(運(yùn)行狀態(tài))轉(zhuǎn)換為 SHUTDOWN狀態(tài)
  • 線程池的shutdownNow()方法,將線程池由RUNNING 或 SHUTDOWN 狀態(tài)轉(zhuǎn)換為 STOP 狀態(tài)。

注:SHUTDOWN 狀態(tài) 和 STOP 狀態(tài) 先會(huì)轉(zhuǎn)變?yōu)?TIDYING 狀態(tài),最終都會(huì)變?yōu)?TERMINATED

2、ThreadPoolExecutor構(gòu)造函數(shù):

ThreadPoolExecutor繼承自AbstractExecutorService,而AbstractExecutorService實(shí)現(xiàn)了ExecutorService接口。

接下來我們分別講解這些參數(shù)的含義。

2.1)線程池工作原理:

  • corePoolSize :線程池中核心線程數(shù)的最大值
  • maximumPoolSize :線程池中能擁有最多線程數(shù)
  • workQueue:用于緩存任務(wù)的阻塞隊(duì)列

當(dāng)調(diào)用線程池execute() 方法添加一個(gè)任務(wù)時(shí),線程池會(huì)做如下判斷:

  • 如果有空閑線程,則直接執(zhí)行該任務(wù);
  • 如果沒有空閑線程,且當(dāng)前運(yùn)行的線程數(shù)少于corePoolSize,則創(chuàng)建新的線程執(zhí)行該任務(wù);
  • 如果沒有空閑線程,且當(dāng)前的線程數(shù)等于corePoolSize,同時(shí)阻塞隊(duì)列未滿,則將任務(wù)入隊(duì)列,而不添加新的線程;
  • 如果沒有空閑線程,且阻塞隊(duì)列已滿,同時(shí)池中的線程數(shù)小于maximumPoolSize ,則創(chuàng)建新的線程執(zhí)行任務(wù);
  • 如果沒有空閑線程,且阻塞隊(duì)列已滿,同時(shí)池中的線程數(shù)等于maximumPoolSize ,則根據(jù)構(gòu)造函數(shù)中的 handler 指定的策略來拒絕新的任務(wù)。

2.2)KeepAliveTime:

  • keepAliveTime :表示空閑線程的存活時(shí)間
  • TimeUnit unit :表示keepAliveTime的單位

當(dāng)一個(gè)線程無事可做,超過一定的時(shí)間(keepAliveTime)時(shí),線程池會(huì)判斷,如果當(dāng)前運(yùn)行的線程數(shù)大于 corePoolSize,那么這個(gè)線程就被停掉。所以線程池的所有任務(wù)完成后,它最終會(huì)收縮到 corePoolSize 的大小。

注:如果線程池設(shè)置了allowCoreThreadTimeout參數(shù)為true(默認(rèn)false),那么當(dāng)空閑線程超過keepaliveTime后直接停掉。(不會(huì)判斷線程數(shù)是否大于corePoolSize)即:最終線程數(shù)會(huì)變?yōu)?。

2.3)workQueue 任務(wù)隊(duì)列:

  • workQueue :它決定了緩存任務(wù)的排隊(duì)策略

ThreadPoolExecutor線程池推薦了三種等待隊(duì)列,它們是:SynchronousQueue 、LinkedBlockingQueue 和 ArrayBlockingQueue。

1)有界隊(duì)列:

  • SynchronousQueue :一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,每個(gè)插入操作必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作一直處于 阻塞狀態(tài),吞吐量通常要高于LinkedBlockingQueue,靜態(tài)工廠方法 Executors.newCachedThreadPool 使用了這個(gè)隊(duì)列。
  • ArrayBlockingQueue:一個(gè)由數(shù)組支持的有界阻塞隊(duì)列。此隊(duì)列按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序。一旦創(chuàng)建了這樣的緩存區(qū),就不能再增加其容量。試圖向已滿隊(duì)列中放入元素會(huì)導(dǎo)致操作受阻塞;試圖從空隊(duì)列中提取元素將導(dǎo)致類似阻塞。

2)無界隊(duì)列:

  • LinkedBlockingQueue:基于鏈表結(jié)構(gòu)的無界阻塞隊(duì)列,它可以指定容量也可以不指定容量(實(shí)際上任何無限容量的隊(duì)列/棧都是有容量的,這個(gè)容量就是Integer.MAX_VALUE)
  • PriorityBlockingQueue:是一個(gè)按照優(yōu)先級(jí)進(jìn)行內(nèi)部元素排序的無界阻塞隊(duì)列。隊(duì)列中的元素必須實(shí)現(xiàn) Comparable 接口,這樣才能通過實(shí)現(xiàn)compareTo()方法進(jìn)行排序。優(yōu)先級(jí)最高的元素將始終排在隊(duì)列的頭部;PriorityBlockingQueue 不會(huì)保證優(yōu)先級(jí)一樣的元素的排序。

注意:keepAliveTime和maximumPoolSize及BlockingQueue的類型均有關(guān)系。如果BlockingQueue是無界的,那么永遠(yuǎn)不會(huì)觸發(fā)maximumPoolSize,自然keepAliveTime也就沒有了意義。

2.4)threadFactory:

  • threadFactory :指定創(chuàng)建線程的工廠。(可以不指定)

如果不指定線程工廠時(shí),ThreadPoolExecutor 會(huì)使用ThreadPoolExecutor.defaultThreadFactory 創(chuàng)建線程。默認(rèn)工廠創(chuàng)建的線程:同屬于相同的線程組,具有同為 Thread.NORM_PRIORITY 的優(yōu)先級(jí),以及名為 “pool-XXX-thread-” 的線程名(XXX為創(chuàng)建線程時(shí)順序序號(hào)),且創(chuàng)建的線程都是非守護(hù)進(jìn)程。

2.5)handler 拒絕策略:

  • handler :表示當(dāng) workQueue 已滿,且池中的線程數(shù)達(dá)到 maximumPoolSize 時(shí),線程池拒絕添加新任務(wù)時(shí)采取的策略。(可以不指定)

策略

BB

ThreadPoolExecutor.AbortPolicy()

拋出RejectedExecutionException異常。默認(rèn)策略

ThreadPoolExecutor.CallerRunsPolicy()

由向線程池提交任務(wù)的線程來執(zhí)行該任務(wù)

ThreadPoolExecutor.DiscardPolicy()

拋棄當(dāng)前的任務(wù)

ThreadPoolExecutor.DiscardOldestPolicy()

拋棄最舊的任務(wù)(最先提交而沒有得到執(zhí)行的任務(wù))

最科學(xué)的的還是 AbortPolicy 提供的處理方式:拋出異常,由開發(fā)人員進(jìn)行處理。

3、常用方法:

除了在創(chuàng)建線程池時(shí)指定上述參數(shù)的值外,還可在線程池創(chuàng)建以后通過如下方法進(jìn)行設(shè)置。

此外,還有一些方法:

  • getCorePoolSize():返回線程池的核心線程數(shù),這個(gè)值是一直不變的,返回在構(gòu)造函數(shù)中設(shè)置的coreSize大小;
  • getMaximumPoolSize():返回線程池的最大線程數(shù),這個(gè)值是一直不變的,返回在構(gòu)造函數(shù)中設(shè)置的coreSize大?。?/li>
  • getLargestPoolSize():記錄了曾經(jīng)出現(xiàn)的最大線程個(gè)數(shù)(水位線);
  • getPoolSize():線程池中當(dāng)前線程的數(shù)量;
  • getActiveCount():Returns the approximate(近似) number of threads that are actively executing tasks;
  • prestartAllCoreThreads():會(huì)啟動(dòng)所有核心線程,無論是否有待執(zhí)行的任務(wù),線程池都會(huì)創(chuàng)建新的線程,直到池中線程數(shù)量達(dá)到 corePoolSize;
  • prestartCoreThread():會(huì)啟動(dòng)一個(gè)核心線程(同上);
  • allowCoreThreadTimeOut(true):允許核心線程在KeepAliveTime時(shí)間后,退出;

4、Executors類:

Executors類的底層實(shí)現(xiàn)便是ThreadPoolExecutor! Executors 工廠方法有:

  • Executors.newCachedThreadPool():無界線程池,可以進(jìn)行自動(dòng)線程回收
  • Executors.newFixedThreadPool(int):固定大小線程池
  • Executors.newSingleThreadExecutor():單個(gè)后臺(tái)線程

它們均為大多數(shù)使用場(chǎng)景預(yù)定義了設(shè)置。不過在阿里java文檔中說明,盡量不要用該類創(chuàng)建線程池。

二、線程池相關(guān)接口介紹:

1、ExecutorService接口:

該接口是真正的線程池接口。上面的ThreadPoolExecutor以及下面的ScheduledThreadPoolExecutor都是該接口的實(shí)現(xiàn)類。改接口常用方法:

  • Future<?> submit(Runnable task):提交Runnable任務(wù)到線程池,返回Future對(duì)象,由于Runnable沒有返回值,也就是說調(diào)用Future對(duì)象get()方法返回null;
  • <T> Future<T> submit(Callable<T> task):提交Callable任務(wù)到線程池,返回Future對(duì)象,調(diào)用Future對(duì)象get()方法可以獲取Callable的返回值;
  • <T> Future<T> submit(Runnable task,T result):提交Runnable任務(wù)到線程池,返回Future對(duì)象,調(diào)用Future對(duì)象get()方法可以獲取Runnable的參數(shù)值;
  • invokeAll(collection of tasks)/invokeAll(collection of tasks, long timeout, TimeUnit unit):invokeAll會(huì)按照任務(wù)集合中的順序?qū)⑺械腇uture添加到返回的集合中,該方法是一個(gè)阻塞的方法。只有當(dāng)所有的任務(wù)都執(zhí)行完畢時(shí),或者調(diào)用線程被中斷,又或者超出指定時(shí)限時(shí),invokeAll方法才會(huì)返回。當(dāng)invokeAll返回之后每個(gè)任務(wù)要么返回,要么取消,此時(shí)客戶端可以調(diào)用get/isCancelled來判斷具體是什么情況。
  • invokeAny(collection of tasks)/invokeAny(collection of tasks, long timeout, TimeUnit unit):阻塞的方法,不會(huì)返回 Future 對(duì)象,而是返回集合中某一個(gè)Callable 對(duì)象的結(jié)果,而且無法保證調(diào)用之后返回的結(jié)果是哪一個(gè) Callable,如果一個(gè)任務(wù)運(yùn)行完畢或者拋出異常,方法會(huì)取消其它的 Callable 的執(zhí)行。和invokeAll區(qū)別是只要有一個(gè)任務(wù)執(zhí)行完了,就把結(jié)果返回,并取消其他未執(zhí)行完的任務(wù);同樣,也帶有超時(shí)功能;
  • shutdown():在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任;
  • shutdownNow():停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù);
  • isTerminated():測(cè)試是否所有任務(wù)都執(zhí)行完畢了;
  • isShutdown():測(cè)試是否該ExecutorService已被關(guān)閉。

1.1)submit方法示例:

我們知道,線程池接口中有以下三個(gè)主要方法,接下來我們看一下具體示例:

1)Callable:

public static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 50, 300, TimeUnit.SECONDS, 
			new ArrayBlockingQueue<Runnable>(50),  
			new ThreadFactory(){ public Thread newThread(Runnable r) {
                return new Thread(r, "schema_task_pool_" + r.hashCode());
            }}, new ThreadPoolExecutor.DiscardOldestPolicy());
public static void callableTest() {
	int a = 1;
	//callable
	Future<Boolean> future = threadPool.submit(new Callable<Boolean>(){
		@Override
		public Boolean call() throws Exception {
			int b = a + 100;
			System.out.println(b);
			return true;
		}
	});
	try {
		System.out.println("feature.get");
		Boolean boolean1 = future.get();
		System.out.println(boolean1);
	} catch (InterruptedException e) {
		System.out.println("InterruptedException...");
		e.printStackTrace();
	} catch (ExecutionException e) {
		System.out.println("execute exception...");
		e.printStackTrace();
	} 
}

2)Runnable:

public static void runnableTest() {
	int a = 1;
	//runnable
	Future<?> future1 = threadPool.submit(new Runnable(){
		@Override
		public void run() {
			int b = a + 100;
			System.out.println(b);
		}
	});
	try {
		System.out.println("feature.get");
		Object x = future1.get(900,TimeUnit.MILLISECONDS);
		System.out.println(x);//null
	} catch (InterruptedException e) {
		e.printStackTrace();
	} catch (ExecutionException e) {
		System.out.println("execute exception...");
		e.printStackTrace();
	} catch (TimeoutException e) {
		e.printStackTrace();
	}
}

3)Runnable+result:

class RunnableTask implements Runnable {
	Person p;
	RunnableTask(Person p) {
		this.p = p;
	}
	@Override
	public void run() {
		p.setId(1);
		p.setName("Runnable Task...");
	}
}
class Person {
	private Integer id;
	private String name;
	public Person(Integer id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + "]";
	}
}
public static void runnableTest2() {
	//runnable + result
	Person p = new Person(0,"person");
	Future<Person> future2 = threadPool.submit(new RunnableTask(p),p);
	try {
		System.out.println("feature.get");
		Person person = future2.get();
		System.out.println(person);
	} catch (InterruptedException e) {
		e.printStackTrace();
	} catch (ExecutionException e) {
		e.printStackTrace();
	}
}

1.2)線程池執(zhí)行時(shí),Callable的call方法(Runnable的run方法)拋出異常后,會(huì)出現(xiàn)什么?

在上面的例子中我們可以看到,線程池?zé)o論是執(zhí)行Callable還是Runnable,調(diào)用返回的Future對(duì)象get()方法時(shí)需要處理兩種異常(如果是調(diào)用get(timeout)方法,需要處理三種異常),如下:

//在線程池上運(yùn)行
Future<Object> future = threadPool.submit(callable);
try {
	System.out.println("feature.get");
	Object x = future.get(900,TimeUnit.MILLISECONDS);
	System.out.println(x);
} catch (InterruptedException e) {
	e.printStackTrace();
} catch (ExecutionException e) {
	System.out.println("execute exception...");
	e.printStackTrace();
} catch (TimeoutException e) {
	e.printStackTrace();
}
  • 如果get方法被打斷,進(jìn)入InterruptedException異常;
  • 如果線程執(zhí)行過程(call、run方法)中拋出異常,進(jìn)入ExecutionException異常;
  • 如果get方法超時(shí),進(jìn)入TimeoutException異常;

1.3)submit()和execute()方法區(qū)別:

ExecutorService、ScheduledExecutorService接口的submit()和execute()方法都是把任務(wù)提交到線程池中,但二者的區(qū)別是

  • 接收的參數(shù)不一樣,execute只能接收Runnable類型、submit可以接收Runnable和Callable兩種類型;
  • submit有返回值,而execute沒有返回值;submit方便Exception處理;

1)submit方法內(nèi)部實(shí)現(xiàn):

其實(shí)submit方法也沒有什么神秘的,就是將我們的任務(wù)封裝成了RunnableFuture接口(繼承了Runnable、Future接口),再調(diào)用execute方法,我們看源碼:

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);  //轉(zhuǎn)成 RunnableFuture,傳的result是null
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

2)newTaskFor方法內(nèi)部實(shí)現(xiàn):

newTaskFor方法是new了一個(gè)FutureTask返回,所以三個(gè)方法其實(shí)都是把task轉(zhuǎn)成FutureTask,如果task是Callable,就直接賦值,如果是Runnable 就轉(zhuǎn)為Callable再賦值。

當(dāng)submit參數(shù)是Callable 時(shí):

    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;      
    }

當(dāng)submit參數(shù)是Runnable時(shí):

   // 按順序看,層層調(diào)用
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);  //轉(zhuǎn) runnable 為 callable 
        this.state = NEW; 
    }
   // 以下為Executors中的方法
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
    static final class RunnableAdapter<T> implements Callable<T> {  //適配器
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {   
            task.run();
            return result;
        }
    }

看了源碼就揭開了神秘面紗了,就是因?yàn)镕uture需要返回結(jié)果,所以內(nèi)部task必須是Callable,如果task是Runnable 就偷天換日,在Runnable 外面包個(gè)Callable馬甲,返回的結(jié)果在構(gòu)造時(shí)就寫好。

參考:搞懂Runnable、Callable、Future、FutureTask 及應(yīng)用_趕路人兒的博客-CSDN博客

1.4)ScheduledExecutorService接口:

繼承ExecutorService,并且提供了按時(shí)間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:

  • schedule(task, initDelay): 安排所提交的Callable或Runnable任務(wù)在initDelay指定的時(shí)間后執(zhí)行;
  • scheduleAtFixedRate():安排所提交的Runnable任務(wù)按指定的間隔重復(fù)執(zhí)行;
  • scheduleWithFixedDelay():安排所提交的Runnable任務(wù)在每次執(zhí)行完后,等待delay所指定的時(shí)間后重復(fù)執(zhí)行;

注:該接口的實(shí)現(xiàn)類是ScheduledThreadPoolExecutor。

2、Callable接口:

jdk1.5以后創(chuàng)建線程可以通過一下方式:

  • 繼承Thread類,實(shí)現(xiàn)void run()方法;
  • 實(shí)現(xiàn)Runnable接口,實(shí)現(xiàn)void run()方法;
  • 實(shí)現(xiàn)Callable接口,實(shí)現(xiàn)V call() Throws Exception方法

1)Callable和Runnale接口區(qū)別:

  • Callable可以拋出異常,和Future、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果;
  • Runnable沒有返回結(jié)果,異常只能內(nèi)部消化;

2)執(zhí)行Callable的線程的方法可以通過以下兩種方式:

  • 借助FutureTask,使用Thread的start方法來執(zhí)行;
  • 加入到線程池中,使用線程池的execute或submit執(zhí)行;

注:Callable無法直接使用Thread來執(zhí)行;

我們都知道,Callable帶有返回值的,如果我們不需要返回值,卻又想用Callable該如何做?

jdk中有個(gè)Void類型(大寫V),但必須也要return null。

threadpool.submit(new Callable<Void>() {
    @Override
    public Void call() {
        //...
        return null;
    }
});

3)通過Executors工具類可以把Runnable接口轉(zhuǎn)換成Callable接口:

Executors中的callable方法可以將Runnable轉(zhuǎn)成Callable,如下:

public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
}

RunnableAdapter類在上面已經(jīng)看過源碼,原理就是將返回值result作為成員變量,通過參數(shù)傳遞進(jìn)去,進(jìn)而實(shí)現(xiàn)了Runnable可以返回值。

示例:

public static void test5() {
    	Person p = new Person(0,"person");
    	RunnableTask runnableTask = new RunnableTask(p);//創(chuàng)建runnable
    	Callable<Person> callable = Executors.callable(runnableTask,p);//轉(zhuǎn)換
    	Future<Person> future1 = threadPool.submit(callable);//在線程池上執(zhí)行Callable
    	try {
			Person person = future1.get();
			System.out.println(person);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
    	Runnable runnable = new Runnable() {//創(chuàng)建Runnable
			@Override
			public void run() {
			}
    	};
    	Callable<Object> callable2 = Executors.callable(runnable);//轉(zhuǎn)換
    	Future<Object> future2 = threadPool.submit(callable2);//在線程池上執(zhí)行Callable
    	try {
    		Object o = future2.get();
			System.out.println(o);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
    }

3、Future接口:

3.1)Future是用來獲取異步計(jì)算結(jié)果的接口,常用方法:

  • boolean cancel(boolean mayInterruptIfRunning):試圖取消對(duì)此任務(wù)的執(zhí)行。如果任務(wù)已完成、或已取消,或者由于某些其他原因而無法取消,則此嘗試將失敗。當(dāng)調(diào)用 cancel 時(shí),如果調(diào)用成功,而此任務(wù)尚未啟動(dòng),則此任務(wù)將永不運(yùn)行。如果任務(wù)已經(jīng)啟動(dòng),則 mayInterruptIfRunning 參數(shù)確定是否應(yīng)該以試圖停止任務(wù)的方式來中斷執(zhí)行此任務(wù)的線程。此方法返回后,對(duì) isDone() 的后續(xù)調(diào)用將始終返回 true。如果此方法返回 true,則對(duì) isCancelled() 的后續(xù)調(diào)用將始終返回 true。
  • boolean isCancelled():如果在任務(wù)正常完成前將其取消,則返回 true。
  • boolean isDone():如果任務(wù)已完成,則返回 true,可能由于正常終止、異常或取消而完成,在所有這些情況中,此方法都將返回 true。
  • V get()throws InterruptedException,ExecutionException:獲取異步結(jié)果,此方法會(huì)一直阻塞等到計(jì)算完成;
  • V get(long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException:獲取異步結(jié)果,此方法會(huì)在指定時(shí)間內(nèi)一直阻塞等到計(jì)算完成,超時(shí)后會(huì)拋出超時(shí)異常。

通過方法分析我們也知道實(shí)際上Future提供了3種功能:

  • 能夠中斷執(zhí)行中的任務(wù);
  • 判斷任務(wù)是否執(zhí)行完成;
  • 獲取任務(wù)執(zhí)行完成后額結(jié)果。

但是Future只是一個(gè)接口,我們無法直接創(chuàng)建對(duì)象,因此就需要其實(shí)現(xiàn)類FutureTask登場(chǎng)啦。

3.2)FutureTask類:

1)FutureTask類的實(shí)現(xiàn):

public class FutureTask<V> implements RunnableFuture<V> {
//...
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

FutureTask實(shí)現(xiàn)了Runnable、Future兩個(gè)接口。由于FutureTask實(shí)現(xiàn)了Runnable,因此它既可以通過Thread包裝來直接執(zhí)行,也可以提交給ExecuteService來執(zhí)行。并且還可以直接通過get()函數(shù)獲取執(zhí)行結(jié)果,該函數(shù)會(huì)阻塞,直到結(jié)果返回。因此FutureTask既是Future、Runnable,又是包裝了Callable( 如果是Runnable最終也會(huì)被轉(zhuǎn)換為Callable ), 它是這兩者的合體。

2)FutureTask的構(gòu)造函數(shù):

public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}

3.3)示例:(FutureTask兩種構(gòu)造函數(shù)、以及在Thread和線程池上運(yùn)行)

1)FutureTask包裝過的Callable在Thread、線程池上執(zhí)行:

public static void test3() {
		int a = 1,b = 2;
		Callable<Integer> callable = new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				return a + b;
			}
		};
		//通過futureTask來執(zhí)行Callable
		FutureTask<Integer> futureTask = new FutureTask<>(callable);
		//1.使用Thread執(zhí)行線程
		new Thread(futureTask).start();
		try {
			Integer integer = futureTask.get();
			System.out.println(integer);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		//2.使用線程池執(zhí)行線程
		Executors.newFixedThreadPool(1).submit(futureTask);
		threadPool.shutdown();
		try {
			Integer integer = futureTask.get();
			System.out.println(integer);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		} 
	}

2)FutureTask包裝過的Runnable在Thread、線程池上執(zhí)行:

public static void test4() {
		Person p = new Person(0,"person");
		RunnableTask runnableTask = new RunnableTask(p);
		//創(chuàng)建futureTask來執(zhí)行Runnable
		FutureTask<Person> futureTask = new FutureTask<>(runnableTask,p);
		//1.使用Thread執(zhí)行線程
		new Thread(futureTask).start();
		try {
			Person x = futureTask.get();
			System.out.println(x);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		} 
		//2.使用線程池執(zhí)行線程
		threadPool.submit(futureTask);
		threadPool.shutdown();
		try {
			Person y = futureTask.get();
			System.out.println(y);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}

Person、RunnableTask類同上面的示例中。

到此這篇關(guān)于一文弄懂Java中ThreadPoolExecutor的文章就介紹到這了,更多相關(guān)Java ThreadPoolExecut內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring整合TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度

    Spring整合TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度

    這篇文章主要介紹了Spring整合TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Java Collection集合的三種遍歷方式詳解

    Java Collection集合的三種遍歷方式詳解

    Collection集合遍歷的方式有三種,迭代器foreach/增強(qiáng)for循環(huán)lambda表達(dá)式,這篇文章主要介紹了Java Collection集合的三種遍歷方式,需要的朋友可以參考下
    2022-11-11
  • Java中反射reflect的基礎(chǔ)知識(shí)講解

    Java中反射reflect的基礎(chǔ)知識(shí)講解

    這篇文章主要介紹了Java中反射reflect的基礎(chǔ)知識(shí)講解,Java中的反射,它算是Java當(dāng)中非常底層的一個(gè)技術(shù),平時(shí)我們我們用得不多,實(shí)際上它也的確非常復(fù)雜同時(shí)也難以理解,但是涉及到底層的東西Java都給我們封裝好了,我們直接拿來調(diào)用即可,需要的朋友可以參考下
    2023-10-10
  • Java反射機(jī)制的適用場(chǎng)景及利弊詳解

    Java反射機(jī)制的適用場(chǎng)景及利弊詳解

    這篇文章主要介紹了Java反射機(jī)制的適用場(chǎng)景及利弊詳解,Spring用到很多反射機(jī)制,在xml文件或者properties里面寫好了配置,然后在Java類里面解析xml或properties里面的內(nèi)容,得到一個(gè)字符串,然后用反射機(jī)制,需要的朋友可以參考下
    2023-08-08
  • spring整合redisson開啟緩存方式

    spring整合redisson開啟緩存方式

    這篇文章主要介紹了spring整合redisson開啟緩存方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的實(shí)例代碼

    SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的實(shí)例代碼

    WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作實(shí)例代碼

    Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作實(shí)例代碼

    這篇文章主要給大家介紹了關(guān)于Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決

    Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決

    這篇文章主要給大家介紹了關(guān)于Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-10-10
  • java集合中l(wèi)ist的用法代碼示例

    java集合中l(wèi)ist的用法代碼示例

    這篇文章主要介紹了java集合中l(wèi)ist的用法代碼示例,分享了相關(guān)代碼,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • java之Thread不捕獲異常默認(rèn)處理邏輯

    java之Thread不捕獲異常默認(rèn)處理邏輯

    這篇文章主要介紹了java之Thread不捕獲異常默認(rèn)處理邏輯,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12

最新評(píng)論