一、手动创建线程的缺点:

        (1)创建多个线程,会消耗许多内存。
        (2)创建多个线程,也非常耗时。
        (3)最重要的是,频繁创建线程,在任务执行完毕之后被回收,对GC也有一定的压力。

二、线程池

        线程池:创建线程变成了从线程池获取空闲的线程,关闭线程变成了向池子中归还线程。
        合理地使用线程池能够带来三个好处:

        (1)降低内存资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

        (2)提高响应速度。在线程池中的线程都是已经被创建好的,我们的任务直接获取一个空闲的线程就能够被执行了。

        (3)提高线程的可管理性。使用线程池可以进行统一分配、调优和监控。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性。

三、线程池的代码

        JDK提供的线程池的继承结构。

        

线程池ThreadPoolExecutor的使用_线程池

ThreadPoolExecutor,看这个名字就知道采用的命令设计模式。

ExecutorService。

ThreadPoolExecutor 的 execute(Runnable)方法 与父类ExecutorService的submit方法的区别

       execute(..) 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功。

get() 方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

线程池ThreadPoolExecutor的使用_java_02

        示例代码

import java.util.concurrent.*;

/**
* Created by jay.zhou on 2018/9/5.
*/
public class aas {
public static void main(String[] args) {
//创建一个线程池对象
/**
* 参数信息:
* int corePoolSize 核心线程大小
* int maximumPoolSize 线程池最大容量大小
* long keepAliveTime 线程空闲时,线程存活的时间
* TimeUnit unit 时间单位
* BlockingQueue<Runnable> workQueue 任务队列。一个阻塞队列
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10));
//另外一种写法,与上述本质为一致:
//ExecutorService pool = Executors.newFixedThreadPool(4);

//执行任务
for (int i = 0; i < 10; i++) {
int index = i;
pool.execute( ()-> System.out.println("i:"+index+"execute!"));
}
//关闭线程池
pool.shutdown();
}
}

四、获取异常信息

       因为ExecutorService的submit()方法会在内部处理异常。所以,我们希望的是能够获取到这个异常信息。

Future future = pool.submit();  再通过 future.get()方法获取其执行情况。

       

ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 2, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10));

//执行任务
Future future = pool.submit(() -> System.out.println(2 / 0));
try {
//查看执行情况,有异常将会在此显示。
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
/**
* java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
* caused by java.lang.ArithmeticException
*/

//将任务换成这个将会无任何打印信息
//pool.submit(() -> System.out.println(2 / 0));

execute方法。