线程池概念介绍

一、初始化线程的四种方式

        1.继承Thread

        2.实现Runnable

        3.实现Callable接口+FutureTask

        4.线程池:两种主要初始化方式Executors.newFixedThreadPool()或new ThreadPoolExecutor()

方式1和方式2:主进程无法获取线程的运算结果。

方式3:主进程可以获取运算结果,但是不利于控制服务器中的线程资源,从而导致服务器资源耗尽。

方式4:线程池性能稳定,可以获取执行结果、捕获异常。但是在业务复杂情况下,一个异步调用可能会依赖于另一个异步调用的执行结果。

简单实用方式

继承Thread

public class ThreadTest {
    public static void main(String[] args) {
        System.out.printf("启动开始----");
        /**
         *  继承Thread
         */
        Thread thread = new Thread01();
        // 启动线程
        thread.start();
        System.out.printf("启动结束----")
    }

    static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.printf("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.printf("运行结果"+i);
        }
    }
    
}

运行结果:

实现Runnable

public class ThreadTest {
    public static void main(String[] args) {
        System.out.printf("启动开始----");
        /**
         *  实现Runnable
         */
        Runnable01 runnable01 = new Runnable01();
        new Thread(runnable01).start();
        System.out.printf("启动结束----");

    }

   
    static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.printf("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.printf("运行结果"+i);

        }
    }
   
}

运行结果:

实现Callable接口+FutureTask

如果使用:futureTask.get()获取结果,将会变成阻塞等待

public class ThreadTest {
    public static void main(String[] args) {
        System.out.printf("启动开始----");

        /**
         * 实现Callable接口+FutureTask
         */
        // FutureTask底层继承Runnable
        FutureTask futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        // 可以会获取返回值,如果获取将会变成阻塞等待
        try {
            // 等待整个线程执行完成,获取返回结果(阻塞等待)
            Object o = futureTask.get();
            System.out.printf("o----"+o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.printf("启动结束----");

    }

    static class Callable01 implements Callable<Integer> {


        @Override
        public Integer call() throws Exception {
            System.out.printf("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.printf("运行结果"+i);
            return i;
        }
    }
}

运行结果:

 线程池

public class ThreadTest {
// 创建线程池
    static ExecutorService service = Executors.newFixedThreadPool(10);
    public static void main(String[] args) {
        System.out.printf("启动开始----");
        /**
         * 线程池
         */
        // submit提交线程有返回参数,execute执行没有返回参数
        service.execute(new Runnable01());

    }
    static class Runnable01 implements Runnable{
        @Override
        public void run() {
            System.out.printf("当前线程:"+Thread.currentThread().getId());
            int i = 10/2;
            System.out.printf("运行结果"+i);

        }
    }
}

二、线程池 

        为什么使用线程池,如果每个业务处理都使用原生的线程方法,会不断占用线程。在高并发环境下会将资源耗尽,无法做到总管理线程。所以我们将所有的多线程异步任务都交给线程池执行

        注意不应该执行每个业务都创建一个池,而是系统里最好控制线程池的数量

 线程池介绍

        1.Executors.newFixedThreadPool,创建一个固定大小的线程池。

        2.ThreadPoolExecutor,创建⼀个抢占式执⾏的线程池,是java中最常用的线程池

        3.Executors.newSingleThreadExecutor,创建⼀个可缓存的线程池。

        4.Executors.newScheduledThreadPool,创建单个线程数的线程池,可保证执行顺序。

        5.scheduleAtFixedRate,创建一个可执行延迟任务的线程池。

        6.Executors.newWorkStealingPool,创建一个⼀个单线程的可以执⾏延迟任务的线程池。

ThreadPoolExecutor为最原始的线程池,也是我们主要使用的线程池。

ThreadPoolExecutor线程池

 创建ThreadPoolExecutor比较复杂,最完整的有七个参数:

        1.corePoolSize:核心线程数,线程池创建好后就准备就绪的线程数量,不会因为空闲而回收,等待接受异步任务执行。(除非设置允许核心线程销毁参数

        2.maximumPoolSize:最大线程数量,线程池允许的最大线程数。控制资源并发。

        3.keepAliveTime:存活时间,当前线程数量大于核心数量,空闲线程等待最长时间,然后释放。

        4.TimeUnit:时间单位,存活时间的时间单位。

        5.BlockingQueue<Runnable>:阻塞队列,如果任务过多,就会将目前多的任务放到队列中。只要有空闲的线程,将会从队列中取出新的任务执行。

        6.ThreadFactory:线程创建工厂。

                --DefaultThreadFactory:默认工厂,创建普通线程。

                --PriorityThreadFactory:自定义工厂,创建具有优先级的线程,可指定线程优先级。

                --CustomizableThreadFactory:自定义工厂,创建自定义的线程,可自定义线程名、优先级、守护线程标志、线程组等属性。

                --NamedThreadFactory:自定义工厂,创建有名字的线程,会为每个线程设置一个名字。

                --SpringThreadFactory:Spring框架提供的线程工厂,用于创建可管理的线程。会创建一个新的线程,并将其注册到Spring的线程管理器中,以便管理线程的状态和执行情况。

        7.RejectedExecutionHandler,如果队列满了,按照指定的拒绝策略,拒绝执行任务。

                --AbortPolicy:默认策略,抛弃策略,当无法执行更多任务时抛弃任务并抛出异常。

                --CallerRunsPolicy:调用者运行策略,当线程池无法处理新任务时,将任务返回给提交任务的线程来同步执行。

                --DiscardPolicy:忽视策略,当线程池无法处理新任务时,直接抛弃,无任何提示。

                --DiscardOldestPolicy:抛弃旧策略,当线程池无法处理新任务时,抛弃队列中最早提交的任务,并尝试重新提交新任务。

运行流程

        1.线程池创建,准备好core数量的核心线程,准备接受任务。

        2.新的任务进来会用core准备好的空闲线程执行。

                (1)core满了,就将再进来的任务放到阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行。

                (2)阻塞队列满了,直接开新线程执行,最大能开到maximumPoolSize指定的数量。

                (3)maximumPoolSize满了就用RejectedExecutionHandler策略拒绝任务。 

                (4)maximumPoolSize都执行好了。最大线程数量空闲的线程会在keepAliveTime指定时间后销毁线程,最终保持到core大小。

为什么使用线程池

降低资源的消耗:

        通过重复利用已经创建好的线程降低线程的创建和销毁带来的损耗。

提高响应速度:

        因为线程池中的线程数没有超过线程池的最大上限时,有的线程处于等待分配任务的状态,当任务来时无需创建新的线程就能执行。

提高线程的可管理性:

        线程池回根据当前系统特点对池内的线程进行优化处理,减少创建和销毁带来的系统开销。无限的创建和销毁线程消耗系统资源、降低系统的稳定性。使用线程池进行统一分配。        

异步处理请移步:

Java线程池异步CompletableFuture,创建一步对象、回调方法、线程串行化、两任务组合、多任务组合-CSDN博客 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值