线程池的学习(四)

一般使用线程池执行任务都是调用的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模式

posted @ 2020-03-29 01:51  An-Optimistic-Person  阅读(111)  评论(0编辑  收藏  举报