Java并发编程之Callable,Future,FutureTask

创建线程:

1. 继承Thread

2. 实现Runnable

仔细观察会发现void run() ,这个方法没有返回值,也就无法获得线程执行结果。

Callable

返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。

Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。

V call()

计算结果,如果无法计算结果,则抛出一个异常。

跟Runnable功能类似,用于创建线程,但是call方法有返回值

V - call 方法的结果类型

Future

接口 Future<V>

V - 此 Future 的 get 方法所返回的结果类型

Future 表示异步计算的结果。它提供了检查计算是否完成的方法【isDone()】,以等待计算的完成,并获取计算的结果【get()】。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。还提供了其他方法,以确定任务是正常完成还是被取消了【isCancelled() 】。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

FutureTask

实现了Future接口

类 FutureTask<V>

类型参数:

V - 此 FutureTask 的 get 方法所返回的结果类型。

可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。

方法 意义
FutureTask(Callable<V> callable) 创建一个 FutureTask,一旦运行就执行给定的 Callable。
FutureTask(Runnable runnable, V result) 创建一个 FutureTask,一旦运行就执行给定的 Runnable,并安排成功完成时 get 返回给定的结果 。
boolean cancel(boolean mayInterruptIfRunning) 试图取消对此任务的执行。
protected void done() 当此任务转换到状态 isDone(不管是正常地还是通过取消)时,调用受保护的方法。
V get() 如有必要,等待计算完成,然后获取其结果。
V get(long timeout, TimeUnit unit) 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。
boolean isCancelled() 如果在任务正常完成前将其取消,则返回 true。
boolean isDone() 如果任务已完成,则返回 true。
void run() 除非已将此 Future 取消,否则将其设置为其计算的结果。
protected boolean runAndReset() 执行计算而不设置其结果,然后将此 Future 重置为初始状态,如果计算遇到异常或已取消,则该操作失败。
protected void set(V v) 除非已经设置了此 Future 或已将其取消,否则将其结果设置为给定的值。

实例

我们可以这样理解,FutureTask就是一个后台线程,它不同于一般的实现Runnable的线程,FutureTask封装了信息,并且会保存结果。当我们对结果感兴趣的任意时刻,可以直接调用get方法。

SwingWorker(实现了Future接口)其实就是一个很好的例子

一方面界面要相应用户的鼠标点击事件,一方面需要去计算耗时的任务(比如计算素数)。如果将计算任务安排在主线程里,就会造成界面的卡死,即相应不了用户的点击事件。因此可以借用SwingWork

public class TestFutureTask
{
    public static void main(String[] args) throws Exception
    {
        System.out.println("Hello World!");
        FutureTask futureTask = new FutureTask(new CalculateTask());
        Thread task = new Thread(futureTask);
        task.start();
        //监控计算任务是否结束
        while(!futureTask.isDone()){
            System.out.println("响应用户其他的需求...");
            //Thread.sleep(300);
        }

        //获取结果,如果结果没有准备好,则会阻塞在这里
        System.out.println(futureTask.get());
    }
}
class CalculateTask implements Callable<List<Integer>>
{
    /*
    *   计算12321可以由那两个素数相加得到
    */
    @Override
    public List<Integer> call() throws Exception{
        List<Integer> list = new ArrayList<Integer>();
        long start = System.currentTimeMillis();
        int count = 0;
        for(int i = 2; i < 12321 ; i ++){
            if(isPrime(i)){
                count++;
                System.out.print(i + "\t");
                if(count % 20 == 0){
                    System.out.println();
                }
            }

        }
        System.out.println("\n共有素数:" + count);
        for(int i = 2; i <= 12321/2 ; i ++){
            //System.out.println(i+","+(12321-i));
            if(isPrime(i) && isPrime(12321 - i)){
                list.add(i);
                list.add(12321 - i);
            }
            //Thread.sleep(500);
        }
        System.out.println("计算结果耗时:" + (System.currentTimeMillis() - start)+"ms");
        return list;
    }
    public static boolean isPrime(int prime){
        int num = (int)Math.sqrt(prime);
        for(int i = 2; i <= Math.sqrt(prime) ; i ++){
            if(prime % i == 0){
                return false;
            }
        }
        return true;
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 13:30:42

Java并发编程之Callable,Future,FutureTask的相关文章

java并发编程之future模式

1.当你想并发去执行一段代码,但是还想获取这段代码的返回结果,那么future多线程模式就可以派上用场了,代码实现如下. public class Client { public Data request() { final FutureData futureData = new FutureData(); new Thread(new Runnable() { @Override public void run() { futureData.setRealData(new RealData()

Java并发编程之volatile的理解

Java并发编程之volatile关键字的理解 Java中每个线程都有自己的工作内存,类比于处理器的缓存,线程的工作内存中保存了被该线程使用到的变量的主内存的拷贝.线程读写变量都是直接在自己的工作内存中进行的,而何时刷新数据(指将修改的结果更新到主存或者把主存的变量读取覆盖掉工作内存中的值)是不确定的. volatile关键字是修饰字段的关键字,貌似是JDK1.5之后才有的,在多线程编程中,很大的几率会用到这个关键字,volatile修饰变量后该变量有这么一种效果:线程每一次读该变量都是直接从主

java并发编程之Master-Worker模式

Master-Worker模式适合在一个任务可以拆分成多个小任务来进行的情况下使用. package cn.fcl.masterworker; import java.util.HashMap; import java.util.Map; import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; public c

Java并发编程之ConcurrentHashMap

ConcurrentHashMap ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和HashTable功能相同但是线程安全的方法.ConcurrentHashMap可以做到读取数据不加锁,并且其内部的结构可以让其在进行写操作的时候能够将锁的粒度保持地尽量地小,不用对整个ConcurrentHashMap加锁. ConcurrentHashMap的内部结构 ConcurrentHashMap为了提高本身的并发能力,在内部采用了一个叫做Segment

java并发编程之Guarded Suspention

当客户端请求速度远远大于服务端的处理速度,这时候就非常适合使用Guarded Suspention模式 package cn.fcl.guardendSuspension; import java.util.ArrayList; import java.util.List; public class RequestQueue { private List<Integer> integers = new ArrayList<Integer>(); public synchronize

Java并发编程之set集合的线程安全类你知道吗

Java并发编程之-set集合的线程安全类 Java中set集合怎么保证线程安全,这种方式你知道吗? 在Java中set集合是 本篇是<凯哥(凯哥Java:kagejava)并发编程学习>系列之<并发集合系列>教程的第二篇: 本文主要内容:Set集合子类底层分别是什么?基于底层为什么set的子类可以存放一个数据?怎么解决set线程安全问题? 一:Set集合子类 Set的三个子类分别是:HaseSet.TreeSet.LinkedHashSet.这三个都是线程不安全的.那么这三个子类

Java并发编程之Condition

1.使用synchronized中的等待和唤醒实现消费者和生产者模式 /** * 使用Synchronized实现消费者生产者模式 */ public class SynchronizedDemo { static List<Integer> list = new ArrayList<Integer>(); private static int maxNum = 5; // 消费者 private void Consumer(String name){ synchronized (

并发编程之Callable异步,Future模式

Callable 在Java中,创建线程一般有两种方式,一种是继承Thread类,一种是实现Runnable接口.然而,这两种方式的缺点是在线程任务执行结束后,无法获取执行结果.我们一般只能采用共享变量或共享存储区以及线程通信的方式实现获得任务结果的目的. 不过,Java中,也提供了使用Callable和Future来实现获取任务结果的操作.Callable用来执行任务,产生结果,而Future用来获得结果. Callable接口的定义如下: public interface Callable<

Java并发编程之Phaser类

Phaser这个类的使用场景为N个线程分阶段并行的问题.有这么一个任务为"做3道题",每个学生一个进程,5个学生可以并行做,这个就是常规的并发,但是如果加一个额外的 限制条件,必须等所有人都做完类第一题,才能开始做第二题,必须等所有人都做完了第二题,才能做第三题,这个问题就转变成了分阶段并发的问题,最适合用Phaser来解题,下面给出源代码,大家可以自己尝试: MyPhaser.java import java.util.concurrent.Phaser; public class