Java ExecutorService四種執行緒池基本介紹以及相關舉例
阿新 • • 發佈:2019-01-23
1、new Thread的弊端
執行一個非同步任務你還只是如下new Thread嗎?
new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub } }).start();
那你就out太多了,new Thread的弊端如下:
a. 每次new Thread新建物件效能差。
b. 執行緒缺乏統一管理,可能無限制新建執行緒,相互之間競爭,及可能佔用過多系統資源導致宕機或oom。
c. 缺乏更多功能,如定時執行、定期執行、執行緒中斷。
相比new Thread,Java提供的四種執行緒池的好處在於:
a. 重用存在的執行緒,減少物件建立、消亡的開銷,效能佳。
b. 可有效控制最大併發執行緒數,提高系統資源的使用率,同時避免過多資源競爭,避免堵塞。
c. 提供定時執行、定期執行、單執行緒、併發數控制等功能。
2、Java 執行緒池
Java通過Executors提供四種執行緒池,分別為:
newCachedThreadPool建立一個可快取執行緒池,如果執行緒池長度超過處理需要,可靈活回收空閒執行緒,若無可回收,則新建執行緒。
newFixedThreadPool 建立一個定長執行緒池,可控制執行緒最大併發數,超出的執行緒會在佇列中等待。
newScheduledThreadPool 建立一個定長執行緒池,支援定時及週期性任務執行。
newSingleThreadExecutor 建立一個單執行緒化的執行緒池,它只會用唯一的工作執行緒來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先順序)執行。
3、以下例子是我在公司編寫程式碼時所執行的基本方案
package com.shuang.executorservice; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * ExecutorService執行緒池的使用 * 這裡只是執行了一個執行緒的任務為例 * @author shuang * */ public class ExecutorServiceTest { //執行緒執行後需要得到的結果之一 private String strString = null; //例項化 private static ExecutorServiceTest INSTANCE = new ExecutorServiceTest(); //獲取單例項 public static ExecutorServiceTest getInstance(){ return INSTANCE; } //構造方法私有化 private ExecutorServiceTest(){ ExecutorService executor = null; try { executor = Executors.newFixedThreadPool(3, new SelfThreadFactory("shuang-thread")); Future<String> future = executor.submit(new TestTask()); strString = future.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }finally { if(executor != null){ executor.shutdown(); } } } public String getStrString(){ return strString; } }
package com.shuang.executorservice;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 執行緒工廠
* @author shuang
*
*/
public class SelfThreadFactory implements ThreadFactory {
//執行緒組
private final ThreadGroup group;
//可以使用院子方式更新的int值。有關院子變數屬性的描述
private final AtomicInteger threadNumber = new AtomicInteger(1);
//執行緒名字首
private final String namePrefix;
/**
* 構造器
* @param name 執行緒名
*/
public SelfThreadFactory(String name) {
//安全管理器,相關介紹可以看APi文件
SecurityManager securityManager = System.getSecurityManager();
group = securityManager == null?Thread.currentThread().getThreadGroup():securityManager.getThreadGroup();
namePrefix = new StringBuilder().append(name).append("-").toString();
}
@Override
public Thread newThread(Runnable target) {
//分配新的Thread物件,以便將target作為其中執行物件。
//將指定的name作為其名稱,作為group所引用的執行緒組的一員,並具有指定的堆疊大小
Thread thread =new Thread(
group,
target,
new StringBuilder().append(namePrefix).append(threadNumber.getAndIncrement()).toString(),
0);
if(thread.isDaemon()){//守護執行緒
thread.setDaemon(false);
}
if(thread.getPriority() != 5){//優先順序
thread.setPriority(5);
}
return thread;
}
}
package com.shuang.executorservice;
import java.util.concurrent.Callable;
/**
* 測試任務類-其中一個
* @author shuang
*
*/
public class TestTask implements Callable<String> {
@Override
public String call() throws Exception {
return "this is OK!";
}
}
package com.shuang.executorservice;
//測試類
public class Test {
public static void main(String[] args) {
System.out.println(ExecutorServiceTest.getInstance().getStrString());
}
}