并发编程Future and Callable

并发编程Future and Callable

目录:

1、Future及Callable基本介绍:

2、主要方法介绍:

3、Callable与Runnable的主要区别:

4、示例代码及运行结果:

 

1、Future及Callable基本介绍:

Future接口:

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。

 继承关系:

java.util.concurrent.Future<V>:V——get方法所返回的结果类型

 使用原因:

获得Callable接口产生的返回值,以便进行后期的处理。

Callable接口:

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

继承关系:

java.util.concurrent.Callable<V>:V——call方法的结果类型

使用原因:

使得线程可以产生返回值。

 

2、主要方法介绍:

Future接口:

boolean cancel(boolean mayInterruptIfRunning):如果线程正在运行则是否中断正在运行的线程,在代码中需要使用if(Thread.currentThread().isInterrupted())进行配合,结果返回true表示成功发送取消任务的命令,无阻塞特性

V get():用于获得Callable的返回值,具有阻塞特性;

V get(long timeout TimeUnit unit):在指定的最大时间内等待获得返回值,超过最大等待时间,则抛出TimeoutException异常,具有阻塞特性

boolean isCancelled():如果在任务正常完成前将其取消,则返回true,无阻塞特性

boolean isDone():如果任务已完成,则返回true,无阻塞特性;

Callable接口:

V call():计算结果,如果无法计算结果,则抛出一个异常;

ExecutorService接口:

void shutdown():执行以前提交的任务,但不再接受提交的新任务。通常shutdown后调用awaitTermination,awaitTermination会阻塞当前线程,等待以前提交的任务执行完,然后才继续向下执行;

<T> Future<T> submit(Callable<T> task):提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future,说明submit()方法支持有返回值的功能;

<T> Future<T> submit(Callable<T> task, T result):第二个参数result可以作为执行结果的返回值,而不需要使用get()方法来进行获得;

boolean awaitTermination(long timeout, TimeUnit unit):当等待超过设定时间时,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false,具有阻塞特性;

Future<?> submit(Runnable task):提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future,说明submit()方法支持无返回值的功能;

 

3、Callable与Runnable的主要区别:

(1)Callable接口的call()方法可以有返回值,而Runnable接口的run()方法没有返回值;

(2)Callable接口的call()方法就可以声明抛出异常,而Runnable接口的run()方法不可以声明抛出异常;

(3)执行完Callable接口中的任务后,返回值是通过Future接口进行获得的。

 

4、示例代码及运行结果:

(1)工程目录图:


图4.1 工程目录图

(2)FutureAndCallableService.java

package com.remoa.futureAndCallable.service;

import java.text.SimpleDateFormat;

public interface FutureAndCallableService {
    SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    void Test();
    
}
(3)Test1MyCallable1.java

package com.remoa.futureAndCallable.domain.callable;

import com.remoa.futureAndCallable.domain.Remoa;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Callable;

public class Test1MyCallable1 implements Callable<List<Remoa>> {
    @Override
    public List<Remoa> call() throws Exception {
        Thread.sleep(500);
        List<Remoa> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            String uuid = UUID.randomUUID().toString().substring(0,10);
            Remoa remoa = new Remoa();
            remoa.setAge(random.nextInt(29) + 1);
            remoa.setName("Remoa" + i);
            remoa.setStudentId(uuid);
            list.add(remoa);
        }
        return list;
    }

}

(4)TestMyCallable2.java

package com.remoa.futureAndCallable.domain.callable;

import com.remoa.futureAndCallable.domain.Remoa;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;

public class Test1MyCallable2 implements Callable<List<Remoa>> {
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public List<Remoa> call() throws Exception {
        Thread.sleep(500);
        List<Remoa> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < 5; i++) {
            if(Thread.currentThread().isInterrupted()){
                System.out.println(Thread.currentThread().getName() + "中断时间为:" + simpleDateFormat.format(new Date()));
                throw new InterruptedException();
            }
            String uuid = UUID.randomUUID().toString().substring(0,10);
            Remoa remoa = new Remoa();
            remoa.setAge(random.nextInt(29) + 1);
            remoa.setName("Remoa" + i);
            remoa.setStudentId(uuid);
            list.add(remoa);
        }
        return list;
    }

}
(5)Test1ServcieImp.java
package com.remoa.futureAndCallable.service.Imp;

import com.remoa.futureAndCallable.domain.callable.Test1MyCallable1;
import com.remoa.futureAndCallable.domain.callable.Test1MyCallable2;
import com.remoa.futureAndCallable.domain.Remoa;
import com.remoa.futureAndCallable.service.FutureAndCallableService;

import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

/**
 * cancel中断线程方法的测试
 */
public class Test1ServiceImp implements FutureAndCallableService {
    public Test1ServiceImp(){
        String date = SIMPLE_DATE_FORMAT.format(new Date());
        System.out.println(date + "开始进行cancel中断线程方法的测试");
    }

    @Override
    public void Test() {
        Test1MyCallable1 test1MyCallable1 = new Test1MyCallable1();
        Test1MyCallable2 test1MyCallable2 = new Test1MyCallable2();
        /*
            int corePoolSize:池中保存的线程数,包括空闲线程
            int maximumPoolSize:池中允许的最大线程数
            long keepAliveTime:当线程数大于池中保存的线程数时,此为终止多余的空闲线程等待新任务的最长时间
            TimeUnit unit:keepAliveTime参数的时间单位
            BlockingQueue<Runnable> workQueue:执行前用于保持任务的队列,此队列仅保持由execute方法提交的Runnable任务
         */
        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
        try {
            Future<List<Remoa>> future1 = executorService.submit(test1MyCallable1);
            System.out.println("(1)先执行具有阻塞特性的get方法:");
            for (int i = 0; i < future1.get().size(); i++) {
                System.out.println(future1.get().get(i));
            }
            System.out.println("成功发送任务取消的命令了吗?" + future1.cancel(true));
            System.out.println("任务是在正常完成前将其取消的吗?" + future1.isCancelled());
        } catch (InterruptedException e) {
            System.out.println("Future1抛出了中断异常");
        } catch (ExecutionException e) {
            System.out.println("Future1抛出了执行异常");
        }finally {
            try {
                Thread.sleep(1000);
                System.out.println("--------------------");
                Future<List<Remoa>> future2 = executorService.submit(test1MyCallable1);
                System.out.println("(2)先执行发送任务取消的命令:");
                System.out.println("成功发送任务取消的命令了吗?" + future2.cancel(true));
                System.out.println("任务是在正常完成前将其取消的吗?" + future2.isCancelled());
                System.out.println("后执行具有阻塞特性的get方法:");
                System.out.println(future2.get().size());
                for (int i = 0; i < future2.get().size(); i++) {
                    System.out.println(future2.get().get(i));
                }
            } catch (InterruptedException e) {
                System.out.println("Future2抛出了中断异常");
            } catch (ExecutionException e) {
                System.out.println("Future2抛出了执行异常");
            } catch(CancellationException e){
                System.out.println("Future2抛出了取消任务异常");
            }finally{
                try {
                    Thread.sleep(1000);
                    System.out.println("--------------------");
                    Future<List<Remoa>> future3 = executorService.submit(test1MyCallable2);
                    System.out.println("(3)配合isInterrupted一起使用");
                    System.out.println("先执行发送任务取消的命令,cancel方法参数选择为false:");
                    //发送取消的命令,发送成功返回true,但是方法参数传的是false,则线程不会中断会一直执行
                    System.out.println("成功发送任务取消的命令了吗?" + future3.cancel(false));
                    System.out.println("任务是在正常完成前将其取消的吗?" + future3.isCancelled());
                    System.out.println("后执行具有阻塞特性的get方法:");
                    for (int i = 0; i < future3.get().size(); i++) {
                        System.out.println(future3.get().get(i));
                    }
                } catch (InterruptedException e) {
                    System.out.println("Future3抛出了中断异常");
                } catch (ExecutionException e) {
                    System.out.println("Future3抛出了执行异常");
                } catch(CancellationException e){
                    System.out.println("Future3抛出了取消任务异常");
                }finally {
                    try {
                        Thread.sleep(1000);
                        System.out.println("--------------------");
                        Future<List<Remoa>> future4 = executorService.submit(test1MyCallable2);
                        System.out.println("(4)配合isInterrupted一起使用");
                        System.out.println("先执行发送任务取消的命令,cancel方法参数选择为true:");
                        //设置了sleep睡眠时间,则线程已经跑完,中断命令不再起作用,将返回false
                        Thread.sleep(800);
                        System.out.println("成功发送任务取消的命令了吗?" + future4.cancel(true));
                        System.out.println("任务是在正常完成前将其取消的吗?" + future4.isCancelled());
                        System.out.println("后执行具有阻塞特性的get方法:");
                        for (int i = 0; i < future4.get().size(); i++) {
                            System.out.println(future4.get().get(i));
                        }
                    } catch (InterruptedException e) {
                        System.out.println("Future4抛出了中断异常");
                    } catch (ExecutionException e) {
                        System.out.println("Future4抛出了执行异常");
                    }
                }
            }
        }
    }

}
运行结果:


图4.2 测试1截图

(6)Test2MyCallable.java

package com.remoa.futureAndCallable.domain.callable;

import com.remoa.futureAndCallable.domain.Remoa;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;

public class Test2MyCallable implements Callable<Remoa>{
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public Remoa call() throws Exception {
        System.out.println(simpleDateFormat.format(new Date()));
        Thread.sleep(10000);
        Remoa remoa = new Remoa();
        remoa.setName("Remoa");
        remoa.setAge(21);
        remoa.setStudentId("3114005847");
        return remoa;
    }

}
(7)Test2ServiceImp.java

package com.remoa.futureAndCallable.service.Imp;

import com.remoa.futureAndCallable.domain.Remoa;
import com.remoa.futureAndCallable.domain.callable.Test2MyCallable;
import com.remoa.futureAndCallable.service.FutureAndCallableService;

import java.util.Date;
import java.util.concurrent.*;

/**
 * Future.get(long timeout, TimeUnit unit)方法的测试
 */
public class Test2ServiceImp implements FutureAndCallableService {
    public Test2ServiceImp(){
        String date = SIMPLE_DATE_FORMAT.format(new Date());
        System.out.println(date + "开始进行get(long timeout, TimeUnit unit)方法的测试");
    }

    @Override
    public void Test() {
        Test2MyCallable myCallable = new Test2MyCallable();
        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        Future<Remoa> future = executorService.submit(myCallable);
        System.out.println("设置在五秒中内等待获得返回值:");
        try {
            System.out.println(future.get(5,TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            System.out.println("Future抛出了线程中断异常");
        } catch (ExecutionException e) {
            System.out.println("Future抛出了执行异常");
        } catch (TimeoutException e) {
            System.out.println("Future抛出了超时异常");
        }
    }

}
运行结果:


图4.3 测试2截图

(8)Test3MyCallable.java

package com.remoa.futureAndCallable.domain.callable;

import com.remoa.futureAndCallable.domain.Remoa;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;

public class Test3MyCallable implements Callable<Remoa> {
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private String username;
    private String studentId;
    private int age;

    public Test3MyCallable(String username, String studentId, int age){
        this.username = username;
        this.studentId = studentId;
        this.age = age;
    }

    @Override
    public Remoa call() throws Exception {
        System.out.println(simpleDateFormat.format(new Date()));
        Remoa remoa = new Remoa();
        remoa.setName(username);
        remoa.setAge(age);
        remoa.setStudentId(studentId);
        return remoa;
    }
}
(9)Test3ServiceImp.java

package com.remoa.futureAndCallable.service.Imp;

import com.remoa.futureAndCallable.domain.Remoa;
import com.remoa.futureAndCallable.domain.callable.Test3MyCallable;
import com.remoa.futureAndCallable.service.FutureAndCallableService;
import com.remoa.futureAndCallable.service.MyRejectedExceptionHandler;

import java.util.Date;
import java.util.concurrent.*;

/**
 * 自定义拒绝策略RejectedExecutionHandler接口使用的测试
 */
public class Test3ServiceImp implements FutureAndCallableService {
    public Test3ServiceImp(){
        String date = SIMPLE_DATE_FORMAT.format(new Date());
        System.out.println(date + "开始进行自定义拒绝策略RejectedExecutionHandler接口使用的测试");
    }

    @Override
    public void Test() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
        executor.setRejectedExecutionHandler(new MyRejectedExceptionHandler());
        ExecutorService executorService = executor;
        Future<Remoa> future1 = executorService.submit(new Test3MyCallable("Remoa1",  "3114005847", 21));
        Future<Remoa> future2 = executorService.submit(new Test3MyCallable("Remoa2",  "3114005848", 22));
        Future<Remoa> future3 = executorService.submit(new Test3MyCallable("Remoa3",  "3114005849", 23));
        try {
            System.out.println(future1.get());
            System.out.println(future2.get());
            System.out.println(future3.get());
        } catch (InterruptedException e) {
            System.out.println("Future1或Future2或Future3发生了中断异常");
        } catch (ExecutionException e) {
            System.out.println("Future1或Future2或Future3发生了执行异常");
        }
        executor.shutdown();
        Future<Remoa> future4 = executorService.submit(new Test3MyCallable("Remoa4",  "3114005850", 24));
        try {
            System.out.println(future4.get());
        } catch (InterruptedException e) {
            System.out.println("Future4发生了中断异常");
        } catch (ExecutionException e) {
            System.out.println("Future4发生了执行异常");
        }
    }

}

(10)MyRejectedExceptionHandler.java

package com.remoa.futureAndCallable.service;

import com.remoa.futureAndCallable.domain.Menu;

import java.util.concurrent.FutureTask;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * RejectedExecutionHandler其主要作用是当线程池关闭后依然后任务要执行时,可以实现一些处理。
 */
public class MyRejectedExceptionHandler implements RejectedExecutionHandler{
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println(((FutureTask)r).toString() + "被拒绝");
        Menu.getMenu();
    }

}

运行结果:
图4.4 测试3截图

(11)Test4MyCallable.java

package com.remoa.futureAndCallable.domain.callable;

import com.remoa.futureAndCallable.domain.Remoa;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;

public class Test4MyCallable implements Callable<List<Remoa>>{
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public List<Remoa> call() throws Exception {
        System.out.println(Thread.currentThread().getName() + ",开始执行的时间为:" + simpleDateFormat.format(new Date()));
        List<Remoa> list = new ArrayList<>();
        Random random = new Random();
        for (int i = 0; i < (random.nextInt(1000) + 10) * 100000; i++) {
            String uuid = UUID.randomUUID().toString().substring(0,10);
            Remoa remoa = new Remoa();
            remoa.setAge(random.nextInt(29) + 1);
            remoa.setName("Remoa" + i);
            remoa.setStudentId(uuid);
            list.add(remoa);
        }
        System.out.println(Thread.currentThread().getName() + ", list's size = " + list.size());
        System.out.println(Thread.currentThread().getName() + "任务结束,结束时间为:" + simpleDateFormat.format(new Date()));
        return list;
    }

}

(12)Test4ServiceImp.java

package com.remoa.futureAndCallable.service.Imp;

import com.remoa.futureAndCallable.domain.callable.Test4MyCallable;
import com.remoa.futureAndCallable.service.FutureAndCallableService;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * ExecutorService的相关方法测试
 */
public class Test4ServiceImp implements FutureAndCallableService {
    public Test4ServiceImp(){
        String date = SIMPLE_DATE_FORMAT.format(new Date());
        System.out.println(date + "开始进行ExecutorService的相关方法的测试");
    }

    @Override
    public void Test() {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        Test4MyCallable callable = new Test4MyCallable();
        try {
            while(true) {
                executorService.submit(callable);
                executorService.submit(callable);
                executorService.submit(callable);
                executorService.submit(callable);
                executorService.submit(callable);
                break;
            }
            executorService.shutdown();
            boolean flag =  executorService.awaitTermination(5, TimeUnit.HOURS);
            if(flag == false){
                executorService.shutdownNow();
                System.out.println("任务超时,未完成!");
            }
            System.out.println("哈哈哈,执行最后的语句了");
        } catch (InterruptedException e) {
            System.out.println("发生了中断异常。");
        }
    }

}

运行结果:


图4.5 测试4截图

(13)Menu.java

package com.remoa.futureAndCallable.domain;

import com.remoa.futureAndCallable.Strategy.ChooserTest;

import java.util.Scanner;

/**
 * 菜单类
 */
public class Menu {
    public static void getMenu(){
        String choiceStr = "";
        Scanner scanner = new Scanner(System.in);
        ChooserTest chooserTest = new ChooserTest();
        while(!choiceStr.equals("0")) {
            System.out.println("-------------测试选项------------------------------------");
            System.out.println("| 0、退出                                               |");
            System.out.println("| 1、测试cancel中断线程方法                              |");
            System.out.println("| 2、测试get(long timeout, TimeUnit unit)方法           |");
            System.out.println("| 3、测试自定义拒绝策略RejectedExecutionHandler接口的使用  |");
            System.out.println("| 4、测试ExecutorService的相关方法                       |");
            System.out.println("--------------------------------------------------------");
            System.out.print("请输入您的选择:");
            choiceStr = scanner.nextLine();
            chooserTest.chooseTestDemo(choiceStr);
        }
    }

}
运行结果:


图4.6 菜单选项截图

(14)Remoa.java

package com.remoa.futureAndCallable.domain;

/**
 * Remoa实体类
 */
public class Remoa {
    private String name;
    private String studentId;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStudentId() {
        return studentId;
    }

    public void setStudentId(String studentId) {
        this.studentId = studentId;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Remoa{" +
                "name='" + name + '\'' +
                ", studentId='" + studentId + '\'' +
                ", age=" + age +
                '}';
    }

}
(15)ChooserTest.java
package com.remoa.futureAndCallable.Strategy;

import com.remoa.futureAndCallable.service.*;
import com.remoa.futureAndCallable.service.Imp.Test1ServiceImp;
import com.remoa.futureAndCallable.service.Imp.Test2ServiceImp;
import com.remoa.futureAndCallable.service.Imp.Test3ServiceImp;
import com.remoa.futureAndCallable.service.Imp.Test4ServiceImp;

/**
 * 测试方法选择器
 */
public class ChooserTest {
    FutureAndCallableService futureAndCallableService = null;
    public void chooseTestDemo(String chooseStr){
        switch(chooseStr){
            case "0":
                System.exit(0);
                break;
            case "1":
                futureAndCallableService = new Test1ServiceImp();
                break;
            case "2":
                futureAndCallableService = new Test2ServiceImp();
                break;
            case "3":
                futureAndCallableService = new Test3ServiceImp();
                break;
            case "4":
                futureAndCallableService = new Test4ServiceImp();
                break;
            default:
                System.out.println("You offer an invalid number of choices!Please try again or input '0' to exit");
                break;
        }
        futureAndCallableService.Test();
    }

}
(16)FutureAndCallableAction.java

package com.remoa.futureAndCallable.action;

import com.remoa.futureAndCallable.domain.Menu;

/**
 * 测试入口类
 */
public class FutureAndCallableAction {
    public static void main(String[] args) {
        Menu.getMenu();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值