线程池的简单使用
概述:线程池就是一个池容器中有多个线程,当需要用到线程的时候,直接到线程池中去取一个线程拿来用就好了,当该线程用完后,该线程并没有被销毁,而是被归还到了线程池中,这样就减少了频繁的创建线程和销毁线程的操作,节约了资源的消耗。
java.util.concurrent->定义了关于线程池的接口
Executors类:
1.方法:static ExecutorService newFixedThreadPool(int nThreads) :获取线程池对象
参数:创建线程池对象的时候,指定线程池有多少个线程。
2.返回值: ExecutorService:才是真正的线程池对象
Future<?> submit(Runnable task):提交线程执行的任务->执行线程任务,执行run方法
Future<?>:接收设置线程任务方法的返回值的,由于重写的run方法无返回值,所以一般我不用写Future
void shutdown() :关闭线程池,一般我们不会去关闭线程池。
使用方式:
/**
创建一个线程类
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"要执行了!");
}
}
//测试类
public class ThreadPoolDemo {
public static void main(String[] args) {
//1.获取ExecutorService对象(获取线程对象,里面初始化有两个线程)
ExecutorService es = Executors.newFixedThreadPool(2);
//2.提交线程任务
es.submit(new MyRunnable());
es.submit(new MyRunnable());
es.submit(new MyRunnable());
//3.关闭线程池
es.shutdown();
}
}
因为目前线程池中只有两个线程,而我们调用了三个任务,它的执行流程是这样的:
Callable接口:类似于Runnable接口,都是一个设置线程任务的接口。
实现Callable接口之后要实现接口中的抽象方法 call() 类似于Runnable中的 run()
注意:call() 方法是有返回值的,它的返回值是一个 V (任意类型)
Future是一个接口,用于接收 submit() 返回的值,如果直接输出Future是一个地址值。
Future接口中的方法:
get() 获取Future中的内容
使用:
public class ExecutorsRandomDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//匿名内部类方式 定义一个生成随机数的线程范围1-0之间的随机数并返回
Callable<Double> c = new Callable() {
@Override
public Double call() throws Exception {
return Math.random();
}
};
//创建线程池对象 池中线程有3个
ExecutorService service = Executors.newFixedThreadPool(3);
//调用Callable线程,会返回一个Future类型的数据
Future<Double> f1 = service.submit(c);
//get()获取线程返回的f1的内容 get方法有两个异常ExecutionException, InterruptedException 直接抛出去
System.out.println(f1.get());
//上述还可以链式调用
Double d = service.submit(c).get();
System.out.println(d);
//关闭线程池
service.shutdown();
}
}
输出结果:
0.1273220550580514
0.4330091060101088
总结:如果线程无返回值的情况下我们可以使用 继承Thread类或实现Runnable接口 的方式
如果线程有返回值的情况下我们可以使用 实现Callable接口 的方式,并且使用Future接收,然后.get()方法获取Future中的内容。