线程池的学习(四)
一般使用线程池执行任务都是调用的execute方法,这个方法定义在Executor接口中:
public interface Executor {
void execute(Runnable command);
}
这个方法是没有返回值的,而且只接受Runnable。
--------------------------------------------------这一章就来说说有返回值的线程调用------------------------------------------------------
先看一下Callable和Runnable两个接口的区别:
public interface Callable<V> {
V call() throws Exception;
}
interface Runnable {
public abstract void run();
}
和明显能看到区别:
1.Callable能接受一个泛型,然后在call方法中返回一个这个类型的值。而Runnable的run方法没有返回值
2.Callable的call方法可以抛出异常,而Runnable的run方法不会抛出异常。
再看接口:Future(通过他可以获得任务执行的返回值。)
定义如下:
public interface Future<V> { boolean cancel(boolean var1); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long var1, TimeUnit var3) throws InterruptedException, ExecutionException, TimeoutException; }
其中的get方法获取的就是返回值。
--------------------------------------------------举个Demo来说明----------------------------------------------
import java.util.concurrent.*;
//通过executor.submit提交一个Callable,返回一个Future,然后通过这个Future的get方法取得返回值。 public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<String> submit = executorService.submit(new TaskThread()); String result = submit.get(); System.out.println(result); } } class TaskThread implements Callable<String>{ @Override public String call() throws Exception { System.out.println("子线程开始了"); Thread.sleep(10000); System.out.println("子线程结束了"); return "ok"; } }
接下来一起看看——get()方法的阻塞性
改造main方法:
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> submit = executorService.submit(new TaskThread());
int a=10,b=20;
int c = a+b;
System.out.println(c);
String result = submit.get();
System.out.println(result);
}
在调用submit.get()之前,加入了要运行的代码,并不会影响到代码的执行,直到获取返回值的时候出现阻塞
再改造main方法:
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> submit = executorService.submit(new TaskThread());
String result = submit.get();
System.out.println(result);int a=10,b=20;
int c = a+b;
System.out.println(c);
}
方法中的最后加了一个计算和输出,运行后发现 调用submit.get(),由于调用的子线程中睡眠了10秒,输出返回值 result 就要等子线程执行完,有返回值了才能继续往下执行。也就是说主线程发生阻塞,会影响到后面的代码执行。
那么怎么对付这个阻塞呢? ——在主线程中在创建个子线程来处理这个submit.get();
public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executorService = Executors.newCachedThreadPool(); Future<String> submit = executorService.submit(new TaskThread()); new Thread(new Runnable() { @Override public void run() { String result = null; try { result = submit.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println(result); } }).start(); int a=10,b=20; int c = a+b; System.out.println(c); }
submit(Runnable task)
因为Runnable是没有返回值的,所以如果submit一个Runnable的话,get得到的为null:
Runnable myRunnable = new Runnable() { @Override public void run() { try { Thread.sleep(2000); System.out.println(Thread.currentThread().getName() + " run time: " + System.currentTimeMillis()); } catch (InterruptedException e) { e.printStackTrace(); } } };
ExecutorService executorService = Executors.newCachedThreadPool();
Future executorService = executor.submit(myRunnable);
System.out.println("获取的返回值: "+future.get()); //null
下一章代码实现Future模式