线程池——Java

一、前言

        在字符串常量池中,字符串常量在java程序运行之前就已经创建好了,等程序运行起来后,就可以直接从常量池中拿到字符串并加载到内存中,这样的设计就省下了字符串的构造与销毁的内存开销。

二、优势

        操作系统由内核与应用程序构成,当一段代码是在应用程序中运行的,那么整个执行过程就是可控的,更加高效;当一段代码在内核中运行时,java程序员就无法监视到程序的执行情况,就导致代码的执行是不可控的。

        对于线程也是同样的,当我们从线程池获取线程时,在应用程序层面就可以完成,消耗的资源更小,同时也是可控的;当在操作系统中创建线程时,就需要内核的配合完成,整个过程是不可控的,也会消耗过多的资源。

        因此,线程池可以高效的地创建、销毁线程。

三、标准库的线程池

1、ThreadPoolExecutor

使用ThreadPoolExecutor创建线程时,涉及到以下七个参数:

1)核心线程数:int corePoolSize

当线程池创建时,这些线程也会随之创建,直到线程池销毁后这些线程才会销毁;

2)最大线程数:int maximumPoolSize

最大线程数 = 核心线程数 + 非核心线程数

非核心线程就是在程序不繁忙的时候就销毁,繁忙时就创建;

3)非核心线程允许空闲的时间:long keepAliveTime
4)上述时间的时间按类型:TimeUnit unit

有秒,分钟,还是其他类型;

5)工作队列(传递任务的阻塞队列):BolckingQueue workQueue

线程池本质上是生产消费模型,调用submit方法即为生产,线程池中的线程即为消耗;

6)线程工厂:ThreadFactory threadFactory

使用工厂模式创建的线程,这里会对线程进行初始化操作;

7)拒绝策略:RejectedExecutionHandler handler

使用submit将任务添加到阻塞队列时,当队列满后就会产生阻塞,但是对于线程池来说不是真的阻塞,而是执行拒绝策略相关的代码,有如下几种拒绝策略:

ThreadPoolExecutor.AbortPolicy(),线程池直接抛出异常;

ThreadPoolExecutor.CallerRunsPolicy(),让调用submit的线程执行任务;

ThreadPoolExecutor.DiscardOldestPolicy(),丢弃最老的任务;

ThreadPoolExecutor.DiscardPolicy(),丢弃最新的任务,即submit的任务

2.Executors

        是线程池的工厂类,使用该类创建线程池,返回的是ExecutorService类型的线程池,有以下几种创建线程池的方式:

1)newFixedThreadPool

创建固定线程数目(核心线程数)的线程池

ExecutorService executorService = Executors.newFixedThreadPool(10);
2)newCachedThreadPool

创建线程数目动态增长的线程池:

ExecutorService executorService = Executors.newCachedThreadPool();

也可以将线程工厂作为参数传入到newCachedThreadPool中;

3)newSingleThreadExecutor

创建单个线程的线程池

ExecutorService executorService = Executors.newSingleThreadExecutor();

四、注意事项

线程池中的线程是前台线程,会阻止线程结束,有如下几种解决方案:

1)setDaemon(true)

将线程设置为后台线程;

2)shutdown()

将线程池中的线程全部关闭,但不能保证所有的任务都执行完;

3)awaitTermination()

确认所有任务都执行完后才关闭线程。

你可能感兴趣的:(java,开发语言)