多线程基础之Future和Callable

JAVA创建线程有三种方式:

1.继承thread类(因为java只能单继承,所以不推荐使用此方式)

2.实现runnable接口

3.实现callable接口


当执行无返回参数的线程时使用runnable比较合适,但是当想要获取线程执行的返回结果时runnable就不能满足需求了,所以java内置了Callable和Future。

demo如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class testMain {

	public static void main(String[] args) {
		Callable<String> callable=new Callable<String>() {
			@Override
			public String call() throws Exception {
					return Thread.currentThread().getName();
				}
			};
				//放入futuretask中
			FutureTask<String> future=new FutureTask<>(callable);
			FutureTask<String> future2=new FutureTask<>(callable);
			//运行futuretask
			new Thread(future).start();
			new Thread(future2).start();
			try {
				//获取futuretask返回结果
				String result=future.get();
				System.out.println(result);
				String result2=future2.get();
				System.out.println(result2);
			} catch (InterruptedException | ExecutionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
	}
}复制代码


控制台输出结果:

Thread-0
Thread-1
复制代码


需要注意的是 future的get方法会阻塞线程直到Future返回运行结果。

例子如下:

import java.text.SimpleDateFormat;
import java.util.Date;
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;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class testMain {
	public static void main(String[] args) {
				Callable<String> callable=new Callable<String>() {
					@Override
					public String call() throws Exception {
						Thread.sleep(10000);
						if(Thread.currentThread().getName().equals("Thread-1"))Thread.sleep(10000);
						return Thread.currentThread().getName();
					}
				};
				//放入futuretask中
				FutureTask<String> future=new FutureTask<>(callable);
				FutureTask<String> future2=new FutureTask<>(callable);
				
				//运行futuretask
				new Thread(future,"Thread-1").start();
				new Thread(future2,"Thread-0").start();
				try {
					//获取futuretask返回结果
					System.out.println("futureStart---"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
					String result=future.get();
					System.out.println("futureEnd---"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
					System.out.println(result);
					System.out.println("future2Start---"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
					String result2=future2.get();
					System.out.println("future2End---"+new SimpleDateFormat("HH:mm:ss").format(new Date()));
					System.out.println(result2);
					
				} catch (InterruptedException | ExecutionException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	}
	
}复制代码

运行结果如下:

futureStart---10:23:55
futureEnd---10:24:15
Thread-1
future2Start---10:24:15
future2End---10:24:15
Thread-0复制代码

这里Thread-1的休眠时间是20秒,Thread-0休眠时间是10秒,当Thread-1运行结束后Thread-0立马就返回了结果。


Java线程池也封装了Future和callable的任务运行。代码如下:

                //创建线程池
                ExecutorService executorService=Executors.newCachedThreadPool();
                Callable<String> callable1=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		Callable<String> callable2=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		Callable<String> callable3=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		Future<String> f1=executorService.submit(callable1);
		Future<String> f2=executorService.submit(callable2);
		Future<String> f3=executorService.submit(callable3);
		try {
			System.out.println("f1---"+f1.get());
			System.out.println("f2---"+f2.get());
			System.out.println("f3---"+f3.get());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}复制代码

运行结果:

f1---pool-1-thread-1
f2---pool-1-thread-2
f3---pool-1-thread-3复制代码

executorService.submit会创建一个FutureTask,将callable放入FutureTask在线程池中运行。

当线程池运行多个callable时想要获得返回结果可以使用for循环获取,但是这样显得很是死板麻烦,java内置了一个ExecutorCompletionService,可以把线程池运行的Future结果放入LinkedBlockingQueue中。

代码如下:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class testMain3 {
	public static void main(String[] args) {
		ExecutorService executorService=Executors.newCachedThreadPool();
		Callable<String> callable1=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		Callable<String> callable2=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		Callable<String> callable3=new Callable<String>(){
			@Override
			public String call() throws Exception {
				return Thread.currentThread().getName();
			}
		};
		ExecutorCompletionService<String> completionService=new ExecutorCompletionService<>(executorService);
		completionService.submit(callable1);
		completionService.submit(callable2);
		completionService.submit(callable3);
		try {
			System.out.println("f1---"+completionService.take().get());
			System.out.println("f2---"+completionService.take().get());
			System.out.println("f3---"+completionService.take().get());
		
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
复制代码


运行结果:

f1---pool-1-thread-1
f2---pool-1-thread-3
f3---pool-1-thread-2
复制代码


completionService封装了poll和take,类似阻塞队列BlockingQueue的用途。

take从队列中获取首位元素,如果队列中没有元素take会阻塞线程直到future返回结果。

poll从队列中获取首位元素,没获取到会返回NullPointerException,可以设置阻塞等待时间。

completionService.poll(9, TimeUnit.SECONDS) //等待9秒复制代码


写到这里也就差不多了,感谢大家的阅读,如有不足之处请指出,谢谢。

参考资料:《java并发编程实战》



转载于:https://juejin.im/post/5cce4da3f265da03a00fe18f

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值