异步任务的四种方式

1. 继承Thread

public class TestDemo {
    public static void main(String[] args) {
        System.out.println("main...start....");
        new Thread01().start();
        System.out.println("main...end....");
    }
    /**
     * 继承Thread
     */
    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
        }
    }
}

2. 实现Runnable接口

public class TestDemo {
    public static void main(String[] args) {
        System.out.println("main...start....");
        new Thread(new Runnable01()).start();
        System.out.println("main...end....");
    }
    /**
     * 实现Runnable接口
     */
    public static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.println("当前线程:" + Thread.currentThread().getId());
        }
    }
}

3. 实现Callable接口 + FutureTask

public class TestDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        FutureTask<Integer> task = new FutureTask<>(new Callable01());
        new Thread(task).start();
        //阻塞式等待
        System.out.println("main...end...." + task.get());
    }

    /**
     * 实现Callable接口 + FutureTask
     */
    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 0;
        }
    }
}

  实现Callable接口的好处在于可以接收返回结果,如果需要使用线程的返回结构会阻塞等待
  
  上面的三种方法,每次执行一个任务就需要开启一个线程,如果在高并发状态下,系统资源很快就会被耗尽,所以在实际使用中推荐使用线程池来实现异步任务
4. 线程池
  通过线程池创建异步任务比较重要,所以接下来会详细说明,使用线程池可以有一下的好处

  1. 降低资源的消耗
  2. 提高响应速度
  3. 提高线程的管理
    1)、创建线程池
    通过Executors工具类创建固定的线程池,例如:
// 带缓存的线程池,可以灵活回收线程
ExecutorService pool1 = Executors.newCachedThreadPool();
// 固定大小的线程池
ExecutorService pool2 = Executors.newFixedThreadPool(10);
// 定时任务的线程池
ScheduledExecutorService pool3 = Executors.newScheduledThreadPool(10);
// 单线程的线程池,从队列中获取任务挨个执行
ExecutorService pool4 = Executors.newSingleThreadExecutor();

通过原生的方式创建线程池,需要了解线程池的7大参数
  int corePoolSize:核心线程数,线程池创建好以后准备就绪的线程数,
  int maximumPoolSize:最大线程数,控制资源
  long keepAliveTime:存活时间,线程空闲时间超过设定的值,该线程就会被释放
  TimeUnit unit:时间单位
  BlockingQueue workQueue:阻塞队列,将多余的任务放在队列中等待执行
  ThreadFactory threadFactory:线程的创建工厂,
  RejectedExecutionHandler handler:当队列满了后,按照指定的拒绝策略拒绝执行任务
异步任务的四种方式_第1张图片

ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
	200,
	10,
	TimeUnit.SECONDS,
	new LinkedBlockingQueue<>(),
	Executors.defaultThreadFactory(),
	new ThreadPoolExecutor.AbortPolicy());

  在使用线程池进行异步任务之前还需要了解一个类—CompletableFuture
  例如我们在执行一个功能时,需要去执行多个小任务,如果使用异步的方式,只需要等待最长的一个执行完,那么整个任务就执行完了,但是小任务之间又有逻辑上的关联,就可以使用CompletableFuture异步编排

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        //无返回值的异步方法
        CompletableFuture.runAsync(()->{
            System.out.println("当前线程:" + Thread.currentThread().getId());
        },pool);
        //有返回值的异步方法
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 0;
        }, pool);
        System.out.println(future.get());
        System.out.println("main...end....");
    }
}

  2)、计算完成时回调方法大概有下面四种方法,其中whenComplete可以处理正常和异常的结果,而exceptionally只处理异常的结果
异步任务的四种方式_第2张图片
异步任务的四种方式_第3张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        //有返回值的异步方法
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 10 / 0;
        }, pool).whenComplete((result, exception) -> {//完成之后的逻辑
            System.out.println("结果是" + result);
            System.out.println("异常是" + exception);
        }).exceptionally(throwable -> {//出现异常的逻辑
            System.out.println("抛出异常,请及时处理");
            return 10;
        });
        System.out.println("main...end....");
    }
}

whenComplete只是感知上一步是否成功,它不能修改返回结果,如果要修改返回结果可以使用exceptionally,也可以使用另一种方法handle
  3)、handle方法
异步任务的四种方式_第4张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool).handle((result, exception) -> {
                    if (result != null) {
                        System.out.println("执行成功");
                        return 1;
                    }
                    if (exception != null) {
                        System.out.println("执行异常");
                        return 0;
                    }
                    return -1;
                });
        System.out.println("main...end...." + future.get());
    }
}

  4)、线程串行方法,就是将需要执行的线程就行排序,先执行谁,然后将它执行的结果给下一个线程使用,进行有序执行
异步任务的四种方式_第5张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool).thenRun(() -> {//thenRun系列的方法不能获取上一步的执行结果,并且无返回值
            System.out.println("执行任务2");
        });

        CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool).thenAccept(result -> {//能接受上一步的返回结果,但是没有返回值
            System.out.println("执行任务3并获取到上一步的结果为:" + result);
        });

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("当前线程:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool).thenApply((result) -> {//既能就收上一步的结果,也能返回值
            System.out.println("执行任务4并获取到上一步的结果为:" + result);
            return 100;
        });
        System.out.println("任务4的返回结果:" + future.get());
        System.out.println("main...end....");
    }
}

  5)、两任务组合,当两个任务都完成后才执行下一个任务
异步任务的四种方式_第6张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程1:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool);

        CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程2:" + Thread.currentThread().getId());
            return "hello";
        }, pool);
        //任务1和2执行完成后执行任务3,不能就收其他任务的返回值
        future01.runAfterBoth(future02, () -> {
            System.out.println("任务线程3:" + Thread.currentThread().getId());
        });
        System.out.println("**********************************************分割线**********************************************");
        //任务1和2执行完成后执行任务4,并就收使用任务1和2的返回值,但是无返回值
        future01.thenAcceptBoth(future02, (f1, f2) -> {
            System.out.println("任务线程4:" + Thread.currentThread().getId());
            System.out.println("获取到其他任务的返回值====>任务1:" + f1 + ",任务2:" + f2);
        });
        System.out.println("**********************************************分割线**********************************************");
        //任务1和2执行完成后执行任务5,并就收使用任务1和2的返回值,有返回值
        CompletableFuture<String> future = future01.thenCombine(future02, (f1, f2) -> {
            System.out.println("任务线程5:" + Thread.currentThread().getId());
            System.out.println("获取到其他任务的返回值====>任务1:" + f1 + ",任务2:" + f2);
            return "任务5";
        });
        System.out.println("任务5的返回值:" + future.get());
        System.out.println("main...end....");
    }
}

  6)、两任务组合,当其中一个任务完成后就执行第三个任务
异步任务的四种方式_第7张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程1:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool);

        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程2:" + Thread.currentThread().getId());
            return "hello";
        }, pool);
        System.out.println("**********************************************分割线**********************************************");
        //当任务1或2执行完成后,执行任务3,不能接收返回值也不能返回值
        future01.runAfterEither(future02, () -> {
            System.out.println("任务线程3:" + Thread.currentThread().getId());
        });
        System.out.println("**********************************************分割线**********************************************");
        //当任务1或2执行完成后,执行任务4,能接收返回值但不能返回值
        future01.acceptEither(future02, (result) -> {
            System.out.println("任务线程4:" + Thread.currentThread().getId());
            System.out.println("就收到的上一步的返回值:" + result.toString());
        });
        System.out.println("**********************************************分割线**********************************************");
        //当任务1或2执行完成后,执行任务5,能接收返回值也能返回值
        CompletableFuture<String> future = future01.applyToEither(future02, (result) -> {
            System.out.println("任务线程5:" + Thread.currentThread().getId());
            System.out.println("就收到的上一步的返回值:" + result.toString());
            return "任务5";
        });
        System.out.println("任务5执行完成后的结果:" + future.get());
        System.out.println("main...end....");
    }
}

  7)、多任务组合
异步任务的四种方式_第8张图片

public class TestDemo {
    /**
     * 创建一个固定大小的池对象,系统中不要太多的池,每个异步任务提交到池中运行
     * 通过Executors工具类创建固定的线程池
     */
    public static ExecutorService pool = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start....");
        CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程1:" + Thread.currentThread().getId());
            return 10 / 2;
        }, pool);
        CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程2:" + Thread.currentThread().getId());
            return "hello";
        }, pool);
        CompletableFuture<Object> future03 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程3:" + Thread.currentThread().getId());
            return "world";
        }, pool);
        CompletableFuture<Object> future04 = CompletableFuture.supplyAsync(() -> {
            System.out.println("任务线程4:" + Thread.currentThread().getId());
            return 666;
        }, pool);
        System.out.println("**********************************************分割线**********************************************");
        //所有任务都完成后才算完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03, future04);
        allOf.get();//阻塞等待所有结果完成
        System.out.println(future01.get());
        System.out.println(future02.get());
        System.out.println(future03.get());
        System.out.println(future04.get());
        //当有一个执行完成就完成了
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02, future03, future04);
        anyOf.get();
        System.out.println("线程返回结果:" + anyOf.get());
        System.out.println("main...end....");
    }
}

你可能感兴趣的:(工具,JUC,异步任务)