异步与线程池
1、初始化线程的4种方式
1)、继承Thread
2)、实现Runnable接口
3)、实现Callable接口+FutureTask(可以拿到返回结果,可以处理异常)
4)、线程池
方式1和方式2:主进程无法获取线程的运算结果。不适合当前场景。
方式3:主进程可以获取线程的运算结果,但是不利于控制服务器中的线程资源。可以导致服务器资源耗尽。
方式4:通过如下两种方式初始化线程池
Executors.newFiexed ThreadPool(3);
//或者
new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit unit, workQueue,threadFactory,handler);方式1、继续Thread
/**
 * @description: 继承Thread
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/3/10 21:06
 * @version: 1.0
 */
public class MyThread {
    public static void main(String[] args) {
        System.out.println("启动main方法开始");
        OneMyThread oneMyThread = new OneMyThread();
        oneMyThread.start();
        System.out.println("结束main方法");
    }
    public static class OneMyThread extends Thread{
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:"+i);
        }
    }
}运行结果:
启动main方法开始
结束main方法
当前线程:22
运行结果:5方式2、实现Runable接口
/**
 * @description: 实现Runnable接口
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/3/10 21:06
 * @version: 1.0
 */
public class MyThread {
    public static void main(String[] args) {
        System.out.println("启动main方法开始");
        
        TwoMyThread twoMyThread = new TwoMyThread();
        new Thread(twoMyThread).start();
        System.out.println("结束main方法");
    }
    /**
     * 实现Runnable接口
     */
    public static class TwoMyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:"+i);
        }
    }
}运行结果:
启动main方法开始
结束main方法
当前线程:22
运行结果:5方式3、实现Callable泛型接口
/**
 * @description: 继承Thread
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/3/10 21:06
 * @version: 1.0
 */
public class MyThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("启动main方法开始");
        FutureTask<Integer> futureTask = new FutureTask<>(new ThreeMyThread());
        new Thread(futureTask).start();
        //等待线程执行完成,返回结果
        Integer i = futureTask.get();
        System.out.println("线程执行完,返回结果:"+i);
        System.out.println("结束main方法");
    }
    /**
     * 实现Callable<T>泛型接口
     */
    public static class ThreeMyThread implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:"+i);
            return i;
        }
    }
}运行结果:
启动main方法开始
当前线程:22
运行结果:5
线程执行完,返回结果:5
结束main方法注意:结果的顺序,可以看到是一个阻塞等待
通过FutureTask类源码可以看到,FutureTask不仅可以接受Callable还可以接收Runnable.
FutureTask源码如下:
public class FutureTask<V> implements RunnableFuture<V> {
    /**
     * Creates a {@code FutureTask} that will, upon running, execute the
     * given {@code Runnable}, and arrange that {@code get} will return the
     * given result on successful completion.
     *
     * @param runnable the runnable task
     * @param result the result to return on successful completion. If
     * you don't need a particular result, consider using
     * constructions of the form:
     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
     * @throws NullPointerException if the runnable is null
     */
    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }FutureTask实现RunnableFuture接口:RunnableFuture最终是继承的Runnable。
package java.util.concurrent;
/**
 * A {@link Future} that is {@link Runnable}. Successful execution of
 * the {@code run} method causes completion of the {@code Future}
 * and allows access to its results.
 * @see FutureTask
 * @see Executor
 * @since 1.6
 * @author Doug Lea
 * @param <V> The result type returned by this Future's {@code get} method
 */
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}方式4、直接提交线程池,线程池会自动开启任务。
每次通过new Thread()创建线程问题:导致资源耗尽。以上三种启动方式都不用。应该将所有异步多线程任务交给线程池执行。
线程池:
package com.yanxizhu.family.booking;
import java.util.concurrent.*;
/**
 * @description: 继承Thread
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/3/10 21:06
 * @version: 1.0
 */
public class MyThread {
    //应保证,当前系统中线程池只有一两个,每个异步任务,提交给线程池自己执行。
    public static ExecutorService executorService = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("启动main方法开始");
        
        executorService.submit(new TwoMyThread()); //有返回值
        //每个异步任务,提交给线程池自己执行。
        executorService.execute(new TwoMyThread());//无返回值
        System.out.println("结束main方法");
    }
    /**
     * 实现Runnable接口
     */
    public static class TwoMyThread implements Runnable {
        @Override
        public void run() {
            System.out.println("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.println("运行结果:"+i);
        }
    }
}
运行结果:
启动main方法开始
结束main方法
当前线程:22
运行结果:5使用线程池带来的好处:
1、降低资源的消耗
通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗
2、提高响应速度
因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行
3、提高线程的可管理性
线程池会根据当前系统特点对池内的线程进行优化处理,减少创建和销毁线程带来的系统开销。无限的创建和销毁线程不仅消耗系统资源,还降低系统的稳定性,使用线程池进行统一分配
总结区别
1、直接继承Thread、实现Runnable接口:不能直接得到返回值。
2、实现Callable泛型接口:可以得到返回值。
3、继承Thread、实现Runnable接口、实现Callable泛型接口,都不能达到控制资源的效果。
4、只有线程池可以控制资源,性能稳定。
 
        
       
     
       
           
           
           
          
评论 (0)