utils包提供开了 ExecutorService 线程池的实现,告急目标是为了重复利用线程,进步体系服从。
Thread是一个重量级的资源,创建、启动以及烧毁都是比力泯灭体系资源的,因此利用线程池来管理线程是一个非常告急的编程风俗。
1、Thread
new Thread(new Runnable() { @Override public void run() { } }).start();直接利用 Thread 的弊端如下:
- 每次new Thread新建对象性能差。
- 线程缺乏统一管理,大概无穷制新建线程,相互之间竞争,及大概占用过多体系资源导致死机或oom。
- 缺乏更多功能,如定时实行、定期实行、线程停止。
2、线程池(ExecutorService、ThreadPool)
(1)newCachedThreadPool
创建一个可缓存线程池,如果线程池长度高出处置处罚需要,可机动采取空闲线程,若无可采取,则新建线程
ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); } }); } cachedThreadPool.shutdown();线程池为无穷大,当实行第二个使命时第一个使命已经完成,会复用实行第一个使命的线程,而不用每次新建线程。
(2)newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(index); } }); } cachedThreadPool.shutdown();这里支持的最大线程数是5, 也可以根据体系而定,获取体系可被利用的历程数
Runtime.getRuntime().availableProcessors()(3)newScheduledThreadPool
创建一个定长线程池,支持定时及周期性使命实行。
界说线程池,最大线程数是5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);延长实行:
scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("delay"); } }, 3, TimeUnit.SECONDS);延长1秒,并每隔3秒定期实行
scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS);关于延长实行和周期性实行我们还会想到Timer
Timer timer = new Timer(); TimerTask timerTask = new TimerTask() { @Override public void run() { } }; timer.schedule(timerTask, 1000, 3000);(4)newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来实行使命,包管全部使命按照指定序次(FIFO, LIFO, 优先级)实行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { @Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }Java提供的四种线程池的优点
- 重用存在的线程,淘汰对象创建、消亡的开销,性能佳。
- 可有用控制最大并发线程数,进步体系资源的利用率,同时制止过多资源竞争,制止堵塞。
- 提供定时实行、定期实行、单线程、并发数控制等功能。
(5)自界说线程池
如果我们不想利用以上4种线程池,可以自界说一个线程池:
/** * 线程池 */public class DefaultPoolExecutor { private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); @Override public Thread newThread(Runnable runnable) { // 线程 return new Thread(runnable, "ThreadName #" + mCount.getAndIncrement()); } }; // 可用处置处罚器的Java假造机的数量 private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); // 最大线程数(最佳线程数 = CPU_COUNT + 1) private static final int MAX_CORE_POOL_SIZE = CPU_COUNT + 1; //空闲时间到达 30s 时,采取空闲线程(每隔30s采取一次) private static final long THREAD_TIMEOUT = 30L; /** * 新建一个线程池 * 每个线程都会斲丧大概1M的内存,利用线程池管理和复用线程 * * @param corePoolSize 线程池巨细 * @return */ public static ThreadPoolExecutor newDefaultPoolExecutor(int corePoolSize) { if (corePoolSize == 0) { return null; } corePoolSize = Math.min(corePoolSize, MAX_CORE_POOL_SIZE); int maximumPoolSize = corePoolSize; // corePoolSize: 当线程池小于corePoolSize时,新提交使命将创建一个新线程实行使命,纵然此时线程池中存在空闲线程 // 当线程池到达corePoolSize时,新提交使命将被放入workQueue中,等待线程池中使命调理实行 // 当workQueue已满,且maximumPoolSize>corePoolSize时,新提交使命会创建新线程实行使命 // 当提交使命数高出maximumPoolSize时,新提交使命由RejectedExecutionHandler处置处罚 // 当线程池中高出corePoolSize线程,空闲时间到达keepAliveTime时,关闭空闲线程 // 当设置allowCoreThreadTimeOut(true)时,线程池中线程空闲时间到达keepAliveTime也将关闭 ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, THREAD_TIMEOUT, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(64), sThreadFactory); threadPoolExecutor.allowCoreThreadTimeOut(true); return threadPoolExecutor; }}扩充:
除了execute可以实行线程池中的线程之外,submit也是可以的
submit的效果和execute是一样的,只是execute没有返回值,而submit有返回值。
(1)Future<?> submit(Runnable task)
Future future1 = singleThreadExecutor.submit(new Runnable() { @Override public void run() { } });(2)<T> Future<T> submit(Runnable task, T result)
Future<String> future = singleThreadExecutor.submit(new Runnable() { @Override public void run() { } }, "A");(3)<T> Future<T> submit(Callable<T> task);
Callable callable = new Callable<String>() { @Override public String call() throws Exception { return "A"; } };
Future<String> future = singleThreadExecutor.submit(callable);如果Future中有值的话可以通过以下代码获取
try { System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }Future的别的操纵如图
[本章完...] |