首页 > 编程 > Java > 正文

JAVA 并发基础-线程池

2019-11-10 20:07:59
字体:
来源:转载
供稿:网友

线程池

线程池会在系统启动时即创建大量空闲线程,然后将一个Runnable/Callable对象提交给线程池,池就会分配/创建一个线程来执行他们的run()/call(),任务执行结束,该线程并不会死亡,而是再次返回池中变为空闲状态,等待执行下一个任务。线程池不仅可以避免每当有新任务就启动一个新线程带来的系统开销,而且可以有效控制系统中并发线程的数量,一旦系统中的线程超过一定数量,将导致系统性能剧烈下降,甚至JVM崩溃,而线程池可以设置最大线程数以防止线程数超标.

java提供java.util.concurrent.Executors工厂类来生产线程池, 该工厂类提供如下静态方法:

方法 释义
static ExecutorService newCachedThreadPool() Creates a thread pool that creates new threads as needed, but will reuse PReviously constructed threads when they are available.
static ExecutorService newFixedThreadPool(int nThreads) Creates a thread pool that reuses a fixed number of threads Operating off a shared unbounded queue.
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
static ExecutorService newSingleThreadExecutor() Creates an Executor that uses a single worker thread operating off an unbounded queue.
static ScheduledExecutorService newSingleThreadScheduledExecutor() Creates a single-threaded executor that can schedule commands to run after a given delay, or to execute periodically.
上面这些方法还有都有一个重载方法,需要使用java.util.concurrent.ThreadFactory参数,ThreadFactory是一个接口,用于自定义线程的创建策略.java.util.concurrent.ExecutorService代表尽快执行任务的线程池,当有任务执行时,只需将RunnableCallable实例submit()给线程池就好(只池中有空闲线程,就立即执行任务),ExecutorService提供如下方法来提交任务:
方法 描述
Future submit(Callabletask) Submits a value-returning task for execution and returns a Future representing the pending results of the task.
Future submit(Runnable task) Submits a Runnable task for execution and returns a Future representing that task.
Futuresubmit(Runnable task, T result) Submits a Runnable task for execution and returns a Future representing that task.

Java为ExecutorService提供了一个java.util.concurrent.ThreadPoolExecutor实现类,该类有如下构造方法:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { // ...} 因此, 如果默认的线程池策略(如最[小/大]线程数/线程等待时间)不能满足我们的需求,我们可以自定义线程池策略.

2. ScheduledExecutorService线程池是ExecutorService的子接口,代表可以在指定延迟后或周期性执行线程任务.它提供了如下方法来提交任务:

方法
V ScheduledFuture V schedule(Callable V callable, long delay, TimeUnit unit)
ScheduledFuture ? schedule(Runnable command, long delay, TimeUnit unit)
ScheduledFuture ? scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
ScheduledFuture ? scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

public class ThreadPoolWithCachedThreadPool { public static void main(String[] args) { ExecutorService pool = getThreadPool(); pool.submit(new ThreadInThreadPool()); pool.submit(new ThreadInThreadPool()); pool.shutdown(); } private static ExecutorService getThreadPool() { return Executors.newCachedThreadPool(new ThreadFactory() { public Thread newThread(Runnable r) { return new Thread(r); } }); // return Executors.newCachedThreadPool(); // return Executors.newFixedThreadPool(2); // return Executors.newSingleThreadExecutor(); } private static class ThreadInThreadPool implements Runnable { public void run() { for (int i = 0; i < 10; ++i) { try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + " " + i); } } }}固定大小的线程池public class FixedSizeThreadPool { public static void main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.newFixedThreadPool(2); //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); //关闭线程池 pool.shutdown(); }}class MyThread extends Thread{ @Override public void run() { System.out.println(Thread.currentThread().getName()+ "正在执行。。。"); }}单线程线程池public class SingleThreadPool { public static void main(String[] args) { //创建一个可重用固定线程数的线程池 ExecutorService pool = Executors.newSingleThreadExecutor(); //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口 Thread t1 = new ThreadInPool(); Thread t2 = new ThreadInPool(); Thread t3 = new ThreadInPool(); //将线程放入池中进行执行 pool.execute(t1); pool.execute(t2); pool.execute(t3); //关闭线程池 pool.shutdown(); }} class ThreadInPool extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行。。。"); } }使用自定义策略的线程池,提交Callable任务public class ThreadPoolUseCustomizePolicy { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService pool = getThreadPool(); Future<Integer> task1 = pool.submit(new ConcreteCallable()); Future<Integer> task2 = pool.submit(new ConcreteCallable()); System.out.println(task1.isDone()); System.out.println(task2.isDone()); pool.shutdown(); System.out.println("task1 " + task1.get()); System.out.println("task2 " + task2.get()); } private static ExecutorService getThreadPool() { return new ThreadPoolExecutor(5, 20, 20L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } private static class ConcreteCallable implements Callable<Integer> { public Integer call() throws Exception { int sum = 0; for (int i = 0; i < 100; ++i) { Thread.sleep(10); sum += i; } return sum; } }}**用完**一个线程池后, 应该调用该线程池的**shutdown()方法**,该方法将启动线程池关闭序列,不再接收新任务,但会将以前所有已提交的任务尽快执行完成.所有任务都执行完,池中所有线程都会死亡.
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表