一、为什么使用线程池
java中经常需要用到多线程来处理一些业务,如果单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理。
java中涉及到线程池的相关类均在jdk1.5开始的 java.util.concurrent(JUC)包中,涉及到的几个核心类及接口包括:Executor、Executors、ExecutorService、ThreadPoolExecutor、FutureTask、Callable、Runnable等。
二、线程池的优势
总体来说,线程池有如下的优势:
(1)降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
(2)提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
(3)提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
2、Executors.newFixedThreadPool()
fixed线程池需要指定生成的线程数量。我们在代码中指定生成10个线程。
public class ThreadPoolDemo01 {
public static void main(String[] args) {
// ExecutorService e1 = Executors.newCachedThreadPool();
ExecutorService e2 = Executors.newFixedThreadPool(10);
// ExecutorService e3 = Executors.newSingleThreadExecutor();
//使用线程
for(int i=0; i<100; i++) {
e2.execute(new Task(i));
}
}
}
class Task implements Runnable{
int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
//打印当前线程的名字
System.out.println(Thread.currentThread().getName() + "-----" + i);
//睡1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程池中只会生成10个线程,如果run方法中睡1秒钟,那么在1s之内只能打印出10个线程名字,我们的代码执行完需要10s。
3、Executors.newSingleThreadExecutor()
这个线程池中只有一个线程,可以理解为fixed的单数版。
public class ThreadPoolDemo01 {
public static void main(String[] args) {
// ExecutorService e1 = Executors.newCachedThreadPool();
// ExecutorService e2 = Executors.newFixedThreadPool(10);
ExecutorService e3 = Executors.newSingleThreadExecutor();
//使用线程
for(int i=0; i<100; i++) {
e3.execute(new Task(i));
}
}
}
class Task implements Runnable{
int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
//打印当前线程的名字
System.out.println(Thread.currentThread().getName() + "-----" + i);
//睡1s
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
每次打印出的线程名字都相同,说明自始至终都使用的用一个线程。1s钟只打印1个名字,代码执行完需要100s(需要等1s后线程回到线程池,才能再使用这个线程)。