JDK 5.0 新增解决线程安全 Callable接口和线程池
在jdk5.0后又新增了两种解决线程安全的问题
一: 实现Callable接口,
实现接口步骤:
1: 创建一个实现Callable接口的实现类 2: 实现Callable接口中的call()方法, 讲此线程需要做的操作声明再这个方法中 3: 创建Callable 接口实现类的对象 4: 将创建对象传递到FutureTask构造器中,创建FutureTask对象 5: 将Future的对象作为参数传递到Thread类中 并调用thread的start()方法 6: 通过get()获取call方法中的返回值
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class CallableTestTwo { public static void main(String[] args) { CallableT callableT = new CallableT(); // 3 : 实例化 实现Callable接口的类的对象 FutureTask futureTask = new FutureTask(callableT); // 4: 传递此对象到FutureTask 中 并实例化 new Thread(futureTask).start(); // 5: 生产对象传递到Thread 中并调用start()方法来启动线程 try { // 6: get获取call方法中抛出的信息 get方法必须搭配try来使用 Object val = futureTask.get(); System.out.println("总和是: "+val); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } class CallableT implements Callable { // 1: 实现Calable接口 @Override public Object call() throws Exception { // 2 :实现接口Callable接口中的call()方法 int num = 0; for (int i = 0; i <= 100; i++) { System.out.println(i); num += i; } return num; } }
如何理解实现Callable接口的方式比创建多线程和实现Runnable接口的方式强大?
如何理解实现Callable接口的方式比创建多线程和实现Runnable接口的方式强大? 1: call方法可以有返回值 2: call方法可以抛出异常被外面的操作捕获, 获取异常信息 3: Callable是支持泛型的
二: 线程池
JDK 5.0起提供了线程池相关API:ExecutorService 和 Executors
ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
ExecutorService 不能直接手动建立洗澡池子(线程)池子, 需要用工具一个铁湫之类的工具(Executors)来帮助建立线程.
Executors工具类的方法
Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池
Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池
Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池
Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运 行命令或者定期地执行。
线程池创建的步骤:
1: ExecutorService 使用工具Executors创建线程池 2: 得到的对象使用对应线程的方法submit()或者execute() 操作对应线程 3: shutdown()停止线程
eg:
public class ExecutorsTest { public static void main(String[] args) { // 提供指定线程池的数量 // ExecutorService service = Executors.newFixedThreadPool(10); // //执行指定的线程的操作,需要提供实现Runnable或者Callable接口的实现的对象 service.submit(); // 适合使用于Callable service.execute(); // 适合适用于Runnable //关闭线程连接 // service.shutdown(); ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new RunnableT()); executorService.submit(new RunnableT()); executorService.shutdown(); } }
import java.util.concurrent.*; public class CallableTestThree { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); RunnableTT runnableTT = new RunnableTT(); CallableTT callableTT = new CallableTT(); executorService.submit(callableTT); // submit可以对Callable 和Runnable接口的实现对象进行操作 executorService.submit(runnableTT); //executorService.execute(callableTT); // execute()不可以获取 callable接口的实现对象 因为他只能对Runnable接口的实现对象进行操作 executorService.shutdown(); } } class RunnableTT implements Runnable{ @Override public void run() { System.out.println("这是取偶数"); for (int i = 0; i <= 100 ; i++) { if(i % 2 == 0){ System.out.println(i); } } } } class CallableTT implements Callable{ @Override public Object call() throws Exception { System.out.println("这是取奇数"); for (int i = 0; i <= 100 ; i++) { System.out.println(i); } return null; } }
Executors工具的操作线程方法一般分为两种
submit(): 一般操作Callable
一般主要是操作Callable接口的线程对象, 偶尔可以用于Runnable接口实现的对象,推荐用Callable接口实现的对象
用来操作实现Callable 接口和Runnable接口的线程对象 , 两者都可以
execute(): 一般操作Runnable
只可以操作实现Runnable的接口线程对象
多线程可以理解为一个公交车 一个人就是线程, 你平时是自己走路快还是坐公交快和便捷呢?
肯定是坐公交,你不需要管线程池的问题 只需要管你自己就好了, 因为池子可以装多个线程公交可以装多个人