1. newCachedThreadPool

  • 特点:newCachedThreadPool创建一个可缓存线程池,如果当前线程池的长度超过了处理的需要时,它可以灵活的回收空闲的线程,当需要增加时, 它可以灵活的添加新的线程,而不会对池的长度作任何限制

  • 缺点:他虽然可以无线的新建线程,但是容易造成堆外内存溢出,因为它的最大值是在初始化的时候设置为 Integer.MAX_VALUE,一般来说机器都没那么大内存给它不断使用。当然知道可能出问题的点,就可以去重写一个方法限制一下这个最大值

  • 总结:线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。

  • 代码示例:

    package com.lijie;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class TestNewCachedThreadPool {
        public static void main(String[] args) {
            // 创建无限大小线程池,由jvm自动回收
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
            for (int i = 0; i < 10; i++) {
                final int temp = i;
                newCachedThreadPool.execute(new Runnable() {
                    public void run() {
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                        }
                        System.out.println(Thread.currentThread().getName() + ",i==" + temp);
                    }
                });
            }
        }
    }
    

2.newFixedThreadPool

  • 特点:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。定长线程池的大小最好根据系统资源进行设置。

  • 缺点:线程数量是固定的,但是阻塞队列是无界队列。如果有很多请求积压,阻塞队列越来越长,容易导致OOM(超出内存空间)

  • 总结:请求的挤压一定要和分配的线程池大小匹配,定线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

Runtime.getRuntime().availableProcessors()方法是查看电脑CPU核心数量)

  • 代码示例:

    package com.lijie;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class TestNewFixedThreadPool {
        public static void main(String[] args) {
            ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 10; i++) {
                final int temp = i;
                newFixedThreadPool.execute(new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + ",i==" + temp);
                    }
                });
            }
        }
    }
    

3.newScheduledThreadPool

  • 特点:创建一个固定长度的线程池,而且支持定时的以及周期性的任务执行,类似于Timer(Timer是Java的一个定时器类)

  • 缺点:由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务(比如:一个任务出错,以后的任务都无法继续)。

  • 代码示例:

    package com.lijie;
    
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class TestNewScheduledThreadPool {
        public static void main(String[] args) {
            //定义线程池大小为3
            ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(3);
            for (int i = 0; i < 10; i++) {
                final int temp = i;
                newScheduledThreadPool.schedule(new Runnable() {
                    public void run() {
                        System.out.println("i:" + temp);
                    }
                }, 3, TimeUnit.SECONDS);//这里表示延迟3秒执行。
            }
        }
    }
    

4.newSingleThreadExecutor

  • 特点:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,他必须保证前一项任务执行完毕才能执行后一项。保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

  • 缺点:缺点的话,很明显,他是单线程的,高并发业务下有点无力

  • 总结:保证所有任务按照指定顺序执行的,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它

  • 代码示例:

    package com.lijie;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class TestNewSingleThreadExecutor {
        public static void main(String[] args) {
            ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
            for (int i = 0; i < 10; i++) {
                final int index = i;
                newSingleThreadExecutor.execute(new Runnable() {
                    public void run() {
                        System.out.println(Thread.currentThread().getName() + " index:" + index);
                        try {
                            Thread.sleep(200);
                        } catch (Exception e) {
                        }
                    }
                });
            }
        }
    }
    

线程池都有哪些状态?

  • RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
  • SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
  • STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
  • TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
  • TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。

线程池中 submit() 和 execute() 方法有什么区别?

  • 相同点:
    • 相同点就是都可以开启线程执行池中的任务。
  • 不同点:
    • 接收参数:execute()只能执行 Runnable 类型的任务。submit()可以执行 Runnable 和 Callable 类型的任务。
    • 返回值:submit()方法可以返回持有计算结果的 Future 对象,而execute()没有
    • 异常处理:submit()方便Exception处理


作者:小杰要吃蛋
链接:https://juejin.cn/post/6844904125755293710
来源:掘金