java多线程--Callable、Future

Java 实现多线程的二种方式:

方式一:继承Thread类
方式二:实现Runnable接口

示例代码如下:

  // 方式一:继承Thread类
        Thread thread01 = new Thread() {
            @Override
            public void run() {
                System.out.println("线程二:hello");
            }
        };
        thread01.start();

        // 方式二:实现Runnable接口
        Thread thread02 = new Thread(() -> System.out.println("线程三:hello"));
        thread02.start();

这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果。

自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果。

下面就来了解下Callable与Runnable

Callable 与 Runnable

Runnable接口,来自java.lang.Runnable,只声明了run()方法

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

由于run()方法返回值为void类型,所以在执行完任务之后无法返回任何结果。

Callable接口,来自java.util.concurrent.Callable<V>,也只声明了一个call()方法

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}
可以看到,这是一个泛型接口,call()函数返回的类型就是传递进来的V类型。
那么怎么使用Callable呢?一般情况下是配合ExecutorService来使用的
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

接下来了解下Future

Future

Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。

Future类位于java.util.concurrent包下,它是一个接口:

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

 

       boolean cancel(boolean mayInterruptRunning):试图取消该Future关联的Callable任务。

        V get():返回Callable里call()方法的返回值。该方法会导致程序阻塞,必须等到子线程结束时才能得到返回值。

        V get(long timeout,TimeUnit unit):返回Callable里call()方法的返回值。该方法最多让程序等待timeout和unit指定的时间,到达指定时间后还没有得到返回值,将会抛出TimeoutException异常。

        boolean isCancelled():如果Callable任务在正常完成前被取消,则返回true。

        boolean isDone():如果Callable任务已经完成,则返回true。

 

也就是说Future提供了三种功能:

1)判断任务是否完成;

2)能够中断任务;

3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask

FutureTask类实现了RunnableFuture接口。
RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

FutureTask提供了2个构造器:

public FutureTask(Callable<V> callable) {}

public FutureTask(Runnable runnable, V result) {}

事实上,FutureTask是Future接口的一个唯一实现类。

示例:

了解了这些之后,下面是两个Callable的示例

示例一:Thread.start()启动线程

public static void main(String[] args) {

        // 获取线程的返回值
        AtomicInteger atomicInteger = new AtomicInteger(0);

        FutureTask futureTask = new FutureTask(() -> {
            atomicInteger.set(atomicInteger.get() + 1);
            return atomicInteger.get();
        });

        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            System.out.println(
                    futureTask.get()
            );  // 1
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

示例二:通过ExecutorService执行线程

public static void main(String[] args) {

        // 通过ExecutorService执行线程
        AtomicInteger atomicInteger = new AtomicInteger();

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Future submit = executorService.submit(() -> {
            atomicInteger.set(atomicInteger.get() + 1);
            return atomicInteger.get();
        });
        try {
            System.out.println(
                    submit.get()
            );
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

 





posted on 2020-06-30 22:50  小破孩楼主  阅读(234)  评论(0编辑  收藏  举报