一、实现Callable接口创建多线程
1、相比Runnable,Callable功能更强大
①相比run()方法,可以有返回值。
②方法可以抛出异常。
③支持泛型的返回值。
④需要借助FutureTask类, 比如获取返回结果。
2、Future接口
①可以对具体Runnable、Callable任 务的执行结果进行取消、查询是否完成、获取结果等。
②Futrue Task是Futrue接口的唯一的实现类。
③Future Task同时实现了Runnable、Future接口。
④既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。
1 package mydemos; 2 import java.util.concurrent.Callable; 3 import java.util.concurrent.ExecutionException; 4 import java.util.concurrent.FutureTask; 5 6 //1.创建一个实现Callable的实现类 7 class NumThread implements Callable{ 8 //2.实现call方法,将此线程需要执行的操作声明在call()中 9 @Override 10 public Object call() throws Exception { 11 int sum = 0; 12 for (int i = 1; i <= 100; i++) { 13 if(i % 2 == 0){ 14 System.out.println(i); 15 sum += i; 16 } 17 } 18 return sum; 19 } 20 } 21 22 23 public class ThreadNew { 24 public static void main(String[] args) { 25 //3.创建Callable接口实现类的对象 26 NumThread numThread = new NumThread(); 27 //4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象 28 FutureTask futureTask = new FutureTask(numThread); 29 //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start() 30 new Thread(futureTask).start(); 31 32 try { 33 //6.获取Callable中call方法的返回值 34 //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。 35 Object sum = futureTask.get(); 36 System.out.println("总和为:" + sum); 37 } catch (InterruptedException e) { 38 e.printStackTrace(); 39 } catch (ExecutionException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 }
二、使用线程池创建多线程
1、背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。
2、思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。
可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。
3、好处:
①提高响应速度(减少了创建新线程的时间)
②降低资源消耗(重复利用线程池中线程,不需要每次都创建)
③便于线程管理:
corePoolSize:核心池的大小。
maximumPoolSize:最大线程数。
keepAliveTime:线程没有任务时最多保持多长时间后会终止。
三、线程池相关API
1、JDK 5.0起提供了线程池相关API:ExecutorService和Executors。
2、ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor。
①void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
②<T> Future<T> submit(Callable<T> task):执行任务,有返回值,一般用来执行Callable
③void shutdown():关闭连接池。
3、Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池。
①Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池。
②Executors.newFixedThreadPool(n):创建一个可重用固定线程数的线程池。
③Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池。
④Executors.newScheduledThreadPool(n):
创建一个线程池,可在给定延迟后运行命令或者定期地执行。
1 package mydemos; 2 import java.util.concurrent.ExecutorService; 3 import java.util.concurrent.Executors; 4 import java.util.concurrent.ThreadPoolExecutor; 5 6 class NumberThread implements Runnable{ 7 8 @Override 9 public void run() { 10 for(int i = 0;i <= 100;i++){ 11 if(i % 2 == 0){ 12 System.out.println(Thread.currentThread().getName() + ": " + i); 13 } 14 } 15 } 16 } 17 18 class NumberThread1 implements Runnable{ 19 20 @Override 21 public void run() { 22 for(int i = 0;i <= 100;i++){ 23 if(i % 2 != 0){ 24 System.out.println(Thread.currentThread().getName() + ": " + i); 25 } 26 } 27 } 28 } 29 30 public class ThreadPool { 31 32 public static void main(String[] args) { 33 //1. 提供指定线程数量的线程池 34 ExecutorService service = Executors.newFixedThreadPool(10); 35 ThreadPoolExecutor service1 = (ThreadPoolExecutor) service; 36 //设置线程池的属性 37 // System.out.println(service.getClass()); 38 // service1.setCorePoolSize(15); 39 // service1.setKeepAliveTime(); 40 41 42 //2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象 43 service.execute(new NumberThread());//适合适用于Runnable 44 service.execute(new NumberThread1());//适合适用于Runnable 45 46 // service.submit(Callable callable);//适合使用于Callable 47 //3.关闭连接池 48 service.shutdown(); 49 } 50 51 }