线程应用:(六)线程池、Callable与Future
一、线程池
TCP服务器编程模型中,每来一个客户端连接时,服务端就要创建一个新线程为之服务,当与客户端的会话结束时,线程也就结束了。
在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲线程,再把任务交给内部某个空闲的线程,一个线程同时只能执行一个任务,但可以向线程池提交多个任务。
池子里只有3个线程,但有10个任务,所以只有三个任务会被执行,当3个任务执行完,再由线程池对线程分配任务。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class Thread1 { public static void main(String[] args) { //new单一线程池,线程池只有一个线程,但是这个线程死了,会自动补新的线程 //ExecutorService threadPool= Executors.newSingleThreadExecutor(); //new固定数量的线程池 ExecutorService threadPool= Executors.newFixedThreadPool(3); //new缓存的线程池,内部线程个数不定,任务大于线程个数时,自动增加新的线程,任务小于线程个数时,收回线程 //ExecutorService threadPool= Executors.newCachedThreadPool(); //往池子丢10任务,每个对象是一个Runnable for(int i=1;i<=10;i++){ final int task = i; threadPool.execute(new Runnable() { @Override public void run() { for(int j=1;j<=10;j++){ System.out.println(Thread.currentThread().getName()+", looping:"+j+", task:"+task); } } }); } threadPool.shutdown(); //任务都执行完,关闭线程池 //threadPool.shutdownNow(); //立即结束线程 } }
线程池定时器。
//线程池设置了3个线程,一个任务,10s后运行 //线程池定时器,但是这种定时器没有固定时间的定时,要定时凌晨3点,可以把凌晨3点的时间-现在时间 Executors.newScheduledThreadPool(3).schedule( new Runnable() { @Override public void run() { System.out.println("boom!!!"); } }, 10, //常量 TimeUnit.SECONDS); //单位
二、Callable与Future
1)无返回值的情况:用前面execute的方式执行任务是无返回结果的。
2)有返回值的情况:用submit方式,传任务Callable,运行完后返回Future
ExecutorService threadPool = Executors.newSingleThreadExecutor(); Future<String> future = threadPool.submit( new Callable<String>() { @Override public String call() throws Exception { return "hello"; } } ); //future如果还没结果,会一直等,有点鸡肋 System.out.println(future.get());
CompletionService用于得到一组返回结果。
//CompletionService可以获得一组返回结果 //创建一个有10个线程的线程池 ExecutorService threadPool= Executors.newFixedThreadPool(10); CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool); //提交10个任务 for(int i=1;i<=10;i++){ final int seq = i; completionService.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { Thread.sleep(new Random().nextInt(5000)); //让每个任务运行时间不同 return seq; } } ); } //取返回结果,最先拿到运行完的 for(int i=0;i<10;i++){ System.out.println(completionService.take().get()); }