并发线程池示例(两个示例程序分别用线程 及java自带程池执行一样的程序查看时间):
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Long start = System.currentTimeMillis();
        final Random random = new Random();
        final List<Integer> list = new ArrayList<>();
        //循环10万次 创建了 10万零一个线程
        for (int i = 0; i < 100000; i++) {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    list.add(random.nextInt());
                }
            };
            thread.start();
            thread.join();
        }
        //用8秒
        System.out.println("花费的时间"+(System.currentTimeMillis()-start));
        System.out.println("list大小"+list.size());
    }
}
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        Long start =System.currentTimeMillis();
        final Random random = new Random();
        final List<Integer> list = new ArrayList<>();
        //java自带的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //这里也创建了10w个对象,但是这里只创建了两个线程
        for (int i = 0; i < 100000; i++) {
            executorService.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            list.add(random.nextInt());
                        }
                    }
            );
        }
        executorService.shutdown();
        executorService.awaitTermination(1, TimeUnit.DAYS);
        //用25毫秒
        System.out.println("花费时间:"+(System.currentTimeMillis()-start));
        System.out.println("list大小:"+list.size());
    }
}这里为什么创建了10w的对象 只创建了两个线程,因为都是调用的run方法,run()和start方式启动是不一样的;
示例:
public class ThreadDemo extends Thread{
    private String name;
    public ThreadDemo(String name){
        this.name=name;
    }
    @Override
    public void run() {
        System.out.println(name);
    }
    public static void main(String[] args) {
        //方法调用
//        new ThreadDemo("eric").run();
        //线程启动
        new ThreadDemo("lily").start();
        //线程的名字不一样
    }如果调用run方法是调用自己重写的run方法,只有一个线程,debug快照可对比:

 
start()启动是调用另一个线程

 
线程池底层很多是run()方法的调用,这也是为什么线程池相对而言更快一点的原因。
从1.5开始的,针对java线程池的工具类


并不是只要用线程池就一定是最快的,例子如下:
ublic class ThreadPoolTest2 {
    //一般不推荐用java自带工具类写线程池
    public static void main(String[] args) {
        //快
        ExecutorService executorService1 = Executors.newCachedThreadPool();
        //比上面的慢  一共用10个线程去执行那100个任务
        ExecutorService executorService2 = Executors.newFixedThreadPool(10);
        //最慢的     线程池用一个线程去执行这100个任务
        ExecutorService executorService3 = Executors.newSingleThreadExecutor();
        //执行了100个项目 每个项目需要执行三秒,分别用这三种线程池去执行
        for (int i = 0; i < 100; i++) {
//            executorService1.execute(new MyTask(i));
//            executorService2.execute(new MyTask(i));
            executorService3.execute(new MyTask(i));
        }
    }
}
/**
 * 项目
 */
class MyTask implements Runnable {
    int i;
    public MyTask(int i) {
        this.i = i;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"做的第"+i+"个项目");
        //业务逻辑执行3秒
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
 
MAX_VALUE:

核心线程数:0,任务进来后是没有核心线程去做的
会用临时线程去做,目前最大线程数是:MAX_VALUE
任务进来后,由于没有核心线程,所以会先放到工作队列里面workQueue中,这里用的SynchronousQueue<Runnable> 同步队列(典型的生产消费方式),当放了一个任务进来后,就需要消费掉,否则后面的任务没法放进来,相当于只能存一个对象进来,存一个对象进来后,就需要有临时线程去进行消费,执行此任务。
当把任务执行时间注释掉,

就会出现线程复用的情况

由于项目执行很快,一个线程可以做多个任务。这种线程池相对于其他线程池容易造成CPU100%问题,因为最大线程数没有限制

这里用的核心线程数为10,最大线程数也为10(意味着没有临时线程),临时线程存活时间为0,用了无界队列(队列的结构特点是FIFO),这个队列无限大可以接收N个任务放里面

只有10个线程去处理任务

 
只有1个核心线程,最大线程也是1,无界队列,始终只有一个线程去执行任务。

是否需要用线程池,及用哪种线程池,取决于我们项目执行时间的长短
一般都用自定义线程池,可自行规定参数
//自定义线程池 队列指定容量10 额外多出的临时线程生命周期为1秒
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,
        0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10)); 
执行任务的时候,有自己的执行逻辑,30个任务后,拒绝了,最后线程执行队列里面剩余的任务。这里是执行优先级,优先核心、非核心 获取任务执行,都没有 才从队列里面获取任务去进行执行

Executor顶级接口只有一个execute方法,没有返回值,

AbstractExecutorService 实现了接口

 
submit方法调用了execute执行方法,同时有返回值 这也是跟execute方法的一个区别
我们自定义的线程池ThreadPoolExecutor继承自AbstractExecutorService
底层执行原理:

 
 线程池处理流程:
自带拒绝策略:

ThreadPoolExecutor内部有实现4个拒绝策略:
(1)CallerRunsPolicy,由调用execute方法提交任务的线程来执行这个任务;
(2)AbortPolicy,抛出异常RejectedExecutionException拒绝提交任务;
(3)DiscardPolicy,直接抛弃任务,不做任何处理;
(4)DiscardOldestPolicy,去除任务队列中的第一个任务(最旧的),重新提交;
一般都是自定义拒绝策略。




















