线程是调度cpu的最小单元,也叫轻量级的进程。
类型 | 说明 |
---|---|
SingleThreadExecutor | 单一线程的线程池 |
FixedThreadPool | 固定大小的线程池 |
CachedThreadPool | 可缓冲的线程池 |
ScheduledThreadPool | 无限制大小线程池,定时场景 |
单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
public class singleThreadExecutor {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.print(1 + " ");
}
}
});
executor.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.print(2 + " ");
}
}
});
executor.execute(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.print(3 + " ");
}
}
});
executor.shutdown();
}
}
可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
executor.shutdown();//关闭线程
}
}
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待.
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
public class FixedThreadPool {
public static void main(String[] args) {
//因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
ExecutorService executor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
executor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
executor.shutdown();
}
}
创建一个定长线程池,支持定时及周期性任务执行。
public class ScheduledThreadPool {
public static void main(String[] args) {
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);//等待三秒执行
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);//表示延迟1秒后每3秒执行一次。
}
}
//使用给定的初始参数和默认线程工厂以及拒绝的执行处理程序创建新的ThreadPoolExecutor。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
//使用给定的初始参数和默认拒绝执行处理程序创建新的ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
//使用给定的初始参数和默认线程工厂创建一个新的code ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
//使用给定的初始参数创建一个新的ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
主要参数
ThreadPoolExecutor
的allowCoreThreadTimeOut
属性设置为true
时,keepAliveTime
同样会作用于核心线程。TimeUnit .MILLISECONDS
和TimeUnit .SECONDS
。execute
方法提交的Runnable
对象会存储在这个参数中。threadFactory
是一个接口,它只有一个方法: public abstract Thread newThread (Runnable r)
;maxPoolSize
且队列已满。只要满足其中一种时,在使用execute()
来提交新的任务时将会拒绝,而默认的拒绝策略是抛一个RejectedExecutionException
异常。BlockingQueue
是一个特殊的队列,当我们从BlockingQueue
中取数据时,如果BlockingQueue
是空的,
则取数据的操作会进入到阻塞状态,当 BlockingQueue
中有了新数据时,这个取数据的操作又会被重新唤醒。
同理,如果 BlockingQueue
中的数据已经满了,往BlockingQueue
中存数据的操作又会进入阻塞状态,直到 BlockingQueue
中又有新的空间,存数据的操作又会被重新唤醒。它的泛型限定它是用来存放 Runnable
对象的。
BlockingQueue
,ArrayBlockingQueue
的构造函数接受一个int
类型的数据,该数据表示BlockingQueue
的大小,存储在 ArrayBlockingQueue
中的元素按照 FIFO
(先进先出)的方式来进行存取。BlockingQueue
,在LinkedBlockingQueue
的构造方法中可以传一个 int 类型的数据,这样创建出来的 LinkedBlockingQueue
是有大小的,默认LinkedBlockingQueue
的大小就为 Integer.MAX_VALUE
。LinkedBlockingQueue
类似,不同的是PriorityBlockingQueue
中的元素不是按照 FIFO
来排序的,而是按照元素的Comparator
来决定存取顺序的(这个功能也反映了存入 PriorityBlockingQueue
中的数据必须实现了 Comparator 接口)。同步 Queue
,属于线程安全的 BlockingQueue
的一种,在 SynchronousQueue
中,生产者线程的插入操作必须要等待消费者线程的移除操作,Synchronous
内部没有数据缓存空间,因此我们无法对 SynchronousQueue
进行读取或者遍历其中的数据,元素只有在你试图取走的时候才有可能存在。我们可以理解为生产者和消费者互相等待,等到对方之后然后再一起离开。LinkedBlockingQueue
LinkedBlockingQueue
SynchronousQueue
DelayedWorkQueue
使用代码示例
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
BlockingQueue bq = new ArrayBlockingQueue(5);
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 30, 10, TimeUnit.SECONDS, bq);
executor.allowCoreThreadTimeOut(true);
for (int i = 0; i < 30; i++) {
executor.execute(new PrintDate());
}
}
public static class PrintDate implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + ":" + System.currentTimeMillis());
}
}
}
如何设置参数
默认值
corePoolSize=1
queueCapacity=Integer.MAX_VALUE
maxPoolSize=Integer.MAX_VALUE
keepAliveTime=60s
allowCoreThreadTimeout=false
rejectedExecutionHandler=AbortPolicy()
如何来设置
tasks :每秒的任务数,假设为500~1000
taskcost:每个任务花费时间,假设为0.1s
responsetime:系统允许容忍的最大响应时间,假设为1s
到这里线程池的基本使用就差不多了。