线程池
什么是线程池?
其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁的创建和销毁线程对象的操作,无需反复的创建线程而消耗过多的资源
为什么使用线程池?
三个好处:
- 降低资源消耗:减少创建和销毁线程的次数,每个工作线程都可以被重复使用,可执行多个任务
- 提高响应速度:不需要频繁的创建线程,如果有线程可以直接用,不会出现系统僵死
- 提高线程的可管理性(线程池可以约束系统最多只能有多少个线程,不会因为线程过多而死机)
线程池的核心思想:线程复用,同一个线程可以被重复使用,来处理多个任务。
目标:创建一个线程池
Java在Executors类下提供了一个静态方法得到一个线程池的对象:
public static ExecuorService newFIxedThreadPool(int nThread);
ExecutorService 提交线程任务对象执行的方法
线程池对象.submit(线程任务对象);
小结:
- pool.shutdown(); 等待任务执行完毕之后才会关闭线程池
- pool.shutdownNow();立即关闭线程池,无论任务是否完成
线程池的线程可以复用,线程用完以后可以继续去执行其他任务。
创建线程池的例子
public class ThreadPoolsDemo02 {
public static void main(String[] args) {
// a.创建一个线程池,指定线程的固定数量是3.
// new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
ExecutorService pools = Executors.newFixedThreadPool(3);
// b.创建线程的任务对象。
Runnable target = new MyRunnable();
// c.把线程任务放入到线程池中去执行。
pools.submit(target); // 提交任务,此时会创建一个新线程,自动启动线程执行!
pools.submit(target); // 提交任务,此时会创建一个新线程,自动启动线程执行!
pools.submit(target); // 提交任务,此时会创建一个新线程,自动启动线程执行!
pools.submit(target); // 不会再创建新线程,会复用之前的线程来处理这个任务
pools.shutdown(); // 等待任务执行完毕以后才会关闭线程池
//pools.shutdownNow(); // 立即关闭线程池的代码,无论任务是否执行完毕!
}
}
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0 ; i < 5 ; i++ ){
System.out.println(Thread.currentThread().getName()+" => "+i);
}
}
}
实现callable接口创建线程池对象
- 创建线程任务类实现Callable接口
- 创建线程池对象,指定线程数量
- 线程池对象 .submit(线程任务对象),包装成未来任务对象,自动启动线程执行
- 获取线程执行的结果就是 未来任务对象.get() 来获取
实现Callable接口创建线程池
public class ThreadPoolsDemo03 {
public static void main(String[] args) {
// a.创建一个线程池,指定线程的固定数量是3.
// new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
ExecutorService pools = Executors.newFixedThreadPool(3);
Future<String> t1 = pools.submit(new MyCallable(10)); // 提交任务,此时会创建一个新线程,自动启动线程执行!
Future<String> t2 = pools.submit(new MyCallable(20)); // 提交任务,此时会创建一个新线程,自动启动线程执行!
Future<String> t3 = pools.submit(new MyCallable(30)); // 提交任务,此时会创建一个新线程,自动启动线程执行!
Future<String> t4 = pools.submit(new MyCallable(40)); // 复用之前的某个线程
try{
// b.可以得到线程池执行的任务结构
String rs1 = t1.get();
String rs2 = t2.get();
String rs3 = t3.get();
String rs4 = t4.get();
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
System.out.println(rs4);
}catch (Exception e){
e.printStackTrace();
}
}
}
// 1.定义一个线程任务类实现Callable接口 , 申明线程执行的结果类型。
class MyCallable implements Callable<String>{
private int n;
public MyCallable(int n){
this.n = n;
}
// 2.重写线程任务类的call方法,这个方法可以直接返回执行的结果。
@Override
public String call() throws Exception {
int sum = 0 ;
for(int i = 1 ; i <= n ; i++){
System.out.println(Thread.currentThread().getName()+" => "+i);
sum += i ;
}
return Thread.currentThread().getName()+"计算1-"+n+"的和:"+sum;
}
}