多线程常用代码 Future Callable Runable
public class ThreadPoolTest { public static void main(String[] args) throws InterruptedException { ExecutorService threadPool = Executors.newCachedThreadPool();//线程池里面的线程数会动态变化,并可在线程线被移除前重用 for (int i = 1; i <= 3; i ++) { final int task = i; //10个任务 //TimeUnit.SECONDS.sleep(1); threadPool.execute(new Runnable() { //接受一个Runnable实例 public void run() { System.out.println("线程名字: " + Thread.currentThread().getName() + " 任务名为: "+task); } }); } } }
1、Executors 创建可固定数量的线程newFixedThreadPool 代码如下 public class ExecutorsDemo { public static void main(String[] args) throws Exception, ExecutionException { ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); for(int i=0;i<10;i++){ fixedThreadPool.execute(new MyRunable()); } } } class MyRunable implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
@Test public void testFixedDemo01() { ExecutorService executorService = Executors.newFixedThreadPool(4); for(int i = 0;i < 10;i++) { executorService.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " " +" 走啦"); } }); } }
二、执行任务 通过java.util.concurrent.ExecutorService接口对象来执行任务,该接口对象通过工具类java.util.concurrent.Executors的静态方法来创建。 Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。 ExecutorService提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以关闭 ExecutorService,这将导致其停止接受新任务。关闭后,执行程序将最后终止,这时没有任务在执行,也没有任务在等待执行,并且无法提交新任务。 executorService.execute(new TestRunnable()); 1、创建ExecutorService 通过工具类java.util.concurrent.Executors的静态方法来创建。 Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。 比如,创建一个ExecutorService的实例,ExecutorService实际上是一个线程池的管理工具: ExecutorService executorService = Executors.newCachedThreadPool(); ExecutorService executorService = Executors.newFixedThreadPool(3); ExecutorService executorService = Executors.newSingleThreadExecutor(); 2、将任务添加到线程去执行 当将一个任务添加到线程池中的时候,线程池会为每个任务创建一个线程,该线程会在之后的某个时刻自动执行。 三、关闭执行服务对象 executorService.shutdown(); 四、综合实例 package concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by IntelliJ IDEA. * * @author leizhimin 2008-11-25 14:28:59 */ publicclass TestCachedThreadPool { publicstaticvoid main(String[] args) { // ExecutorService executorService = Executors.newCachedThreadPool(); ExecutorService executorService = Executors.newFixedThreadPool(5); // ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 5; i++) { executorService.execute(new TestRunnable()); System.out.println("************* a" + i + " *************"); } executorService.shutdown(); } } class TestRunnable implements Runnable { publicvoid run() { System.out.println(Thread.currentThread().getName() + "线程被调用了。"); while (true) { try { Thread.sleep(5000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } } 运行结果: ************* a0 ************* ************* a1 ************* pool-1-thread-2线程被调用了。 ************* a2 ************* pool-1-thread-3线程被调用了。 pool-1-thread-1线程被调用了。 ************* a3 ************* ************* a4 ************* pool-1-thread-4线程被调用了。 pool-1-thread-5线程被调用了。 pool-1-thread-2 pool-1-thread-1 pool-1-thread-3 pool-1-thread-5 pool-1-thread-4 pool-1-thread-2 pool-1-thread-1 pool-1-thread-3 pool-1-thread-5 pool-1-thread-4
import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ExecutorServiceTest { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); // 创建10个任务并执行 for (int i = 0; i < 10; i++) { // 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中 Future<String> future = executorService.submit(new TaskWithResult(i)); // 将任务执行结果存储到List中 resultList.add(future); } executorService.shutdown(); // 遍历任务的结果 for (Future<String> fs : resultList) { try { System.out.println(fs.get()); // 打印各个线程(任务)执行的结果 } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { executorService.shutdownNow(); e.printStackTrace(); return; } } } } class TaskWithResult implements Callable<String> { private int id; public TaskWithResult(int id) { this.id = id; } /** * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。 * * @return * @throws Exception */ public String call() throws Exception { System.out.println("call()方法被自动调用,干活!!! " + Thread.currentThread().getName()); if (new Random().nextBoolean()) throw new TaskException("Meet error in task." + Thread.currentThread().getName()); // 一个模拟耗时的操作 for (int i = 999999999; i > 0; i--) ; return "call()方法被自动调用,任务的结果是:" + id + " " + Thread.currentThread().getName(); } } class TaskException extends Exception { public TaskException(String message) { super(message); } }
异步模式模式Future(结合Callable可以获取线程返回结果)
submit 和 excute是有啥区别
如果有这样的需求:
多线程实现下载,提高效率。
不论是Thread类还是Runnable接口重写run方法,有个特点就是没有返回值~~~~~~
我都主线程 如何知道子线程程序执行完毕呢? 子线程执行完毕 立马告诉主线程 可以wait 和 notify
在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口。然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果。我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的。
不过,Java中,也提供了使用Callable和Future来实现获取任务结果的操作。Callable用来执行任务,产生结果,而Future用来获得结果。
可以看到,与Runnable接口不同之处在于,call方法带有泛型返回值V。
submit返回 Future类型
package com.toov5.thread; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class CallableThreadTest { public static void main(String[] args) throws InterruptedException,ExecutionException { ExecutorService executorService=Executors.newCachedThreadPool(); //提交时候 线程池开始执行 System.out.println("1主线程开始执行"); Future<String> sFuture = executorService.submit(new TaskCallable()); System.out.println("hhhhh"); String ResultStirng = sFuture.get(); //下面线程执行的结果 System.out.println("2结果:"+ResultStirng); System.out.println("okokokok"); } } class TaskCallable implements Callable<String>{ //可以返回线程结果 @Override public String call() throws Exception { System.out.println("3正在执行任务,请等待五秒"); Thread.sleep(5000); System.out.println("4执行完毕"); return "这是返回结果"; } }
1和2是不需要阻塞的 后面的需要阻塞哈
子线程去执行 主线程爱干满干嘛不用专门去等待 子线程运行完毕 主获取结果
Future常用方法
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。future.isDone()
boolean isCanceller() :如果任务完成前被取消,则返回true。 future.isCanceller()
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(...)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(...)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:
(1)能够中断执行中的任务
(2)判断任务是否执行完成
(3)获取任务执行完成后额结果。
Future模式
Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑
Futrure模式:对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。
在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。
首先客户端向服务器请求RealSubject,但是这个资源的创建是非常耗时的,怎么办呢?这种情况下,首先返回Client一个FutureSubject,以满足客户端的需求,于此同时呢,Future会通过另外一个Thread 去构造一个真正的资源,资源准备完毕之后,在给future一个通知。如果客户端急于获取这个真正的资源,那么就会阻塞客户端的其他所有线程,等待资源准备完毕。