详解Java四种线程池

2,653 阅读2分钟

线程在并发程序中用的比较多,创建线程原始的有最基本的创建方式:

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //todo
            }
        }).start();
    }

但如果通过这样创线程那就有点low了:

1)每次通过new Thread()创建对象性能不佳。

2)线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。

3)缺乏更多功能,如定时执行、定期执行、线程中断。

这里可以用到Java提供的4种线程池来创建,分别为:

  • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。
  • newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO, 优先级)执行。

下面来比较一下这四种线程池:

newCachedThreadPlool:

 public static void main(String[] args) {
     ExecutorService cacheThreadPool = Executors.newCachedThreadPool();
     for (int i=0; i<10; i++){
         final int index = i;
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e){

         }
         cacheThreadPool.execute(new Runnable() {
             @Override
             public void run() {
                 System.out.println("第" +index +"个线程" +Thread.currentThread().getName());
             }
         });
     }
 }

输出结果为:


可以看出当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用去重新创建线程。

newFixedThreadPool:

public static void main(String[] args) {
    ExecutorService fixedThreadPool =Executors. newFixedThreadPool(3);
    for (int i =1; i<=5;i++){
        final int index=i ;
        fixedThreadPool.execute(new Runnable(){
            @Override
            public void run() {
                try {
                    System.out.println("第" +index + "个线程" +Thread.currentThread().getName());
                    Thread.sleep(1000);
                } catch(InterruptedException e ) {
                    
                }
            }
        });
    }
}

fixThreadPool会定义开启的线程数,例子中开启了三个,所以结果是前三个线程执行,第4个线程要等待1秒后执行。

newScheduledThreadPool:

该线程池可以安排在给定延迟后运行命令或者定期地执行。

延迟执行示例

//corePoolSize - 池中所保存的线程数,即使线程是空闲的也包括在内。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

public static void main(String[] args) {
    ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3);
    scheduledThreadPool.schedule(new Runnable(){
        @Override
        public void run() {
            System.out.println("延迟3秒后执行");
        }
    }, 3, TimeUnit.SECONDS);
}

上述实例会在开启3秒后执行。

定期执行示例

public static void main(String[] args) {
    ScheduledExecutorService scheduledThreadPool= Executors.newScheduledThreadPool(3);
    scheduledThreadPool.scheduleAtFixedRate(new Runnable(){
        @Override
        public void run() {
            System.out.println("延迟3秒后执行");
        }
    }, 1, 3, TimeUnit.SECONDS);  //1:initialDelay, 3:period
}

上述示例会在开启后延迟1秒执行,然后每3秒执行一次。

newSingleThreadExecutor:

public static void main(String[] args) {
    ExecutorService singleThreadPool= Executors.newSingleThreadExecutor();
    for(int i=1;i<=5;i++){
        int index=i;
        singleThreadPool.execute(new Runnable(){
            @Override
            public void run() {
                try{
                    System.out.println("第"+index+"个线程");
                    Thread.sleep(2000);
                }catch(InterruptedException e) {
                    e.printStackTrace();
                }
            } });
    }
}


会每2秒创一个线程,而且是顺序的执行各个任务,并且在任意给定的时间不会有多个线程是活动的,其实与newFixedThreadPool(1)效果是一样的。