java线程池

合理利用线程池能够带来三个好处。
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
但是要做到合理的利用线程池,必须对其原理了如指掌。

一、线程池基础

java通过Executors提供四种线程池,分别为:
   1、Executors.newCachedThreadPool(),创建一个可缓存线程池,缓冲池容量大小为Integer.MAX_VALUE,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
   2、Executors.newFixedThreadPool(int) 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
   3、newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
   4、Executors.newSingleThreadExecutor() 创建一个单线程化(容量为1)的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
   1、shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
   2、shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

1.1、Executors.newCachedThreadPool()

创建一个可缓存线程池,缓冲池容量大小为Integer.MAX_VALUE,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            final int index = i;

            //任务提交
            cachedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " : " +index);
                }
            });
        }

        //如果没有结束线程池,线程池一直是启动的。这里shutdown()和shutdownNow都可以用
        cachedThreadPool.shutdown();
    }
}
pool-1-thread-1 : 0
pool-1-thread-5 : 4
pool-1-thread-3 : 2
pool-1-thread-2 : 1
pool-1-thread-4 : 3

而如果有在任务提交时,先睡眠0.5秒,线程池为无限大,当执行第二个任务时第一个任务已经完成会复用执行第一个任务的线程,而不用每次新建线程。

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            final int index = i;
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //任务提交
            cachedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " : " +index);
                }
            });
        }

        //如果没有结束线程池,线程池一直是启动的。这里shutdown()和shutdownNow都可以用
        cachedThreadPool.shutdown();
    }
}
pool-1-thread-1 : 0
pool-1-thread-1 : 1
pool-1-thread-1 : 2
pool-1-thread-1 : 3
pool-1-thread-1 : 4

1.2、Executors.newFixedThreadPool(int)

   创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 7; i++) {
            final int index = i;
            fixedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " : " + index);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        //这里不能这么关闭线程池,不然输出三个语句后
        // 会有三个java.lang.InterruptedException: sleep interrupted异常
        //fixedThreadPool.shutdownNow();
       fixedThreadPool.shutdown();
 }
}
pool-1-thread-1 : 0
pool-1-thread-3 : 2
pool-1-thread-2 : 1
pool-1-thread-3 : 3
pool-1-thread-1 : 4
pool-1-thread-2 : 5
pool-1-thread-3 : 6
因为线程池大小为3,每个任务输出index后sleep 1秒,所以每1秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

下面这种情况是在任务提交前先睡眠0.5秒

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 7; i++) {
            final int index = i;
            try {
                Thread.sleep( 500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            fixedThreadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " : " + index);
                }

            });
        }

        fixedThreadPool.shutdown();
    }
}
pool-1-thread-1 : 0
pool-1-thread-2 : 1
pool-1-thread-3 : 2
pool-1-thread-1 : 3
pool-1-thread-2 : 4
pool-1-thread-3 : 5
pool-1-thread-1 : 6
每隔0.5秒输出一个结果,因为线程池大小为3,这三个线程会循环输出结果

1.3、newScheduledThreadPool(int corePoolSize)

创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        scheduledThreadPool.schedule(new Runnable() { //schedule
            public void run() {
                System.out.println("delay 1 seconds");
            }
        }, 1, TimeUnit.SECONDS);  //表示延迟1秒后执行。

        //没有结果输出
        //scheduledThreadPool.shutdownNow();
        
        scheduledThreadPool.shutdown();
    }
}
定期执行示例代码如下:
public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() { //scheduleAtFixedRate
            public void run() {
                System.out.println(Thread.currentThread().getName() + " : " 
                        +"delay 1 seconds, and excute every 3 seconds");
            }
        }, 1, 3, TimeUnit.SECONDS); //延迟1秒后每3秒执行一次,一直执行

        //不管用哪个,都没有结果
        //scheduledThreadPool.shutdownNow();
        //scheduledThreadPool.shutdown();
    }
}
pool-1-thread-1 : delay 1 seconds, and excute every 3 seconds
pool-1-thread-1 : delay 1 seconds, and excute every 3 seconds
pool-1-thread-2 : delay 1 seconds, and excute every 3 seconds
pool-1-thread-1 : delay 1 seconds, and excute every 3 seconds
pool-1-thread-1 : delay 1 seconds, and excute every 3 seconds
pool-1-thread-1 : delay 1 seconds, and excute every 3 seconds

......

1.4、newSingleThreadExecutor()

创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下

public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            final int index = i;
            singleThreadExecutor.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " : " +index);

                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}
pool-1-thread-1 : 0
pool-1-thread-1 : 1
pool-1-thread-1 : 2
pool-1-thread-1 : 3
pool-1-thread-1 : 4
结果依次输出,相当于顺序执行各个任务。



你可能感兴趣的:(java线程池)