Java进阶-线程池及创建线程池对象的两种方法

线程池

线程池的概述

线程池:装线程对象的容器

线程池的应用场景:
	如果在一个应用程序中需要多次使用一些线程,不使用线程池的话,咱就需要多次创建并销毁这些线程,而创建又销毁又创建...线程的过程会不断消耗内存
	为此产生了线程池这个概念,把这些线程放到线程池中,当有线程任务来的时候,这些线程就出线程池去完成这些线程任务,当线程任务完成了之后,这些线程就再回到线程池中等待下一次的线程任务的到来,线程池规避了创建又销毁又创建线程这些过程,节省了内存损耗,提高了效率

创建线程池对象的两种方法

面向对象的方式创建线程池对象

概述
面向对象的方式创建线程池对象:
    1.Executors工具类调用静态方法获取线程池对象
    2.使用ExecutorService对象调用提交方法并传入线程任务

    Executors.newCachedThreadPool():
        不指定最大线程数的创建线程池的方法
            --->但是该最大线程数不能超过int类型的最大值

    Executors.newFixedThreadPool(int num):
        指定最大线程数的创建线程池的方法
            --->如果线程任务小于该线程池的最大线程数,则只会创建与线程任务数量大小匹配的线程池,是个限制了最大容量的动态的过程
            例如:现在指定了线程池的最大线程数为100,但是只有十个线程任务需要完成,则不会创建最大线程数为100的线程池,而是会创建最大线程数为10的线程池
代码实现
package com.tan.threadpool;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
面向对象的方式创建线程池对象:
    1.Executors工具类调用静态方法获取线程池对象
    2.使用ExecutorService对象调用提交方法并传入线程任务

    Executors.newCachedThreadPool():
        不指定最大线程数的创建线程池的方法
            --->但是该最大线程数不能超过int类型的最大值

    Executors.newFixedThreadPool(int num):
        指定最大线程数的创建线程池的方法
            --->如果线程任务小于该线程池的最大线程数,则只会创建与线程任务数量大小匹配的线程池,是个限制了最大容量的动态的过程
            例如:现在指定了线程池的最大线程数为100,但是只有十个线程任务需要完成,则不会创建最大线程数为100的线程池,而是会创建最大线程数为10的线程池
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        //创建线程池对象:不指定最大线程数的创建线程池的方法
        ExecutorService es1 = Executors.newCachedThreadPool();
        //提交一百个线程任务
        for (int i = 0; i < 100; i++) {
            //提交一个线程任务
            es1.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "执行了");
                }
            });
        }
        //销毁线程池对象:如果不用shutdown(),则需要在执行程序结束后手动关闭程序及线程池对象
        es1.shutdown();


        //创建线程池对象:指定最大线程数的创建线程池的方法
        ExecutorService es2 = Executors.newFixedThreadPool(10);
        //提交一百个线程任务
        for (int i = 0; i < 100; i++) {
            //提交一个线程任务
            es2.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + "执行了");
                }
            });
        }
        //销毁线程池对象:如果不用shutdown(),则需要在执行程序结束后手动关闭程序及线程池对象
        es2.shutdown();

    }
}

面向过程的方式创建线程池对象

概述
ThreadPoolExecutor(int corePoolSize,//核心线程数
                    int maximumPoolSize,//最大线程池中线程个数
                    long keepAliveTime,//临时线程存活时间数值
                    TimeUnit unit,//临时线程存活时间单位
                    BlockingQueue<Runnable> workQueue,//阻塞队列
                    ThreadFactory threadFactory,//线程工厂 -->线程池获取线程对象的地方
                    RejectedExecutionHandler handler)//等待拒绝策略
 用给定的初始参数创建新的 ThreadPoolExecutor。

 注意:
 1.这七个参数中所有的引用数据类型都不能为null
    -->TimeUnit unit不能为null
    -->BlockingQueue<Runnable> workQueue不能为null
    -->ThreadFactory threadFactory不能为null
    -->RejectedExecutionHandler handler不能为null

 2.核心线程数不能比最大线程池中线程个数大 corePoolSize <= maximumPoolSize

 3.long keepAliveTime不能小于0

方便记忆:
场景描述:假如说我们现在需要管理一家餐厅,且规定一个服务员只能服务一个顾客进行点餐、上菜、结账等,正式员工是固定的,
但是旅游旺季的时候,餐厅生意火爆,原有的正式员工忙不过来,那么我们就需要去人力市场雇用临时员工去增加人手。而且顾客
过多的时候,餐厅内的座位是不是就坐满了,人们就需要在餐厅外面排队,但是每天餐厅准备的食物原材料是有限的,只够一定的
顾客进餐,那么我们就需要和超过准备的事物原材料的人数的顾客进行沟通,让其改日再来或者去隔壁餐厅就餐

这里的:
    -->正式员工就可以理解为:int corePoolSize,//核心线程数
    -->员工总人数(正式员工+临时员工)int maximumPoolSize,//最大线程池中线程个数
    -->临时员工雇用的时长:long keepAliveTime,//临时线程存活时间数值 和 TimeUnit unit,//临时线程存活时间单位
    -->餐厅外面排队的顾客:BlockingQueue<Runnable> workQueue,//阻塞队列-->店外排队的人(可以就餐的顾客)
    -->人力市场:ThreadFactory threadFactory,//线程工厂
    -->和超过准备的事物原材料的人数的顾客进行沟通的说辞:RejectedExecutionHandler handler)//等待拒绝策略-->阻塞队列外不能就餐的顾客
    
一共能在本餐厅就餐的顾客数为:员工总人数(正式员工+临时员工) + 店外排队的人(可以就餐的顾客)
        -->int maximumPoolSize + BlockingQueue<Runnable> workQueue


四种等待拒绝策略
ThreadPoolExecutor中四种等待拒绝策略:
1)static class ThreadPoolExecutor.AbortPolicy
          用于被拒绝任务的处理程序,它将抛出 RejectedExecutionException.
          --->推荐使用(及时告知我们,还有线程任务没有完成)
          --->拒绝所有不在线程池及阻塞队列中的线程任务,并报错

2)static class ThreadPoolExecutor.CallerRunsPolicy
          用于被拒绝任务的处理程序,它直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务。
          --->不推荐使用(都不提醒咱部分线程任务没有完成,可能会影响后续代码)
          --->拒绝所有不在线程池及阻塞队列中的线程任务,不报错

3)static class ThreadPoolExecutor.DiscardOldestPolicy
          用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试 execute;如果执行程序已关闭,则会丢弃该任务。
          --->拒绝所有不在线程池及阻塞队列(除了等待最久的线程任务Oldest)中的线程任务,
              并“随机”选取一个在线程池及阻塞队列中的线程任务移除出去,将等待最久的线程任务Oldest添加进来

4)static class ThreadPoolExecutor.DiscardPolicy
          用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。
          --->拒绝所有不在线程池及阻塞队列中的线程任务,并呼叫其他的线程来处理这些线程任务


代码实现
package com.tan.create_threadpool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/*
面向过程的方式创建线程池对象
 ThreadPoolExecutor(int corePoolSize,//核心线程数
                    int maximumPoolSize,//最大线程池中线程个数
                    long keepAliveTime,//临时线程存活时间数值
                    TimeUnit unit,//临时线程存活时间单位
                    BlockingQueue workQueue,//阻塞队列
                    ThreadFactory threadFactory,//线程工厂 -->线程池获取线程对象的地方
                    RejectedExecutionHandler handler)//等待拒绝策略
 用给定的初始参数创建新的 ThreadPoolExecutor。
 */
public class CreateThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,//核心线程个数
                3,//总线程池的大小
                20,//时间数值
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(2),//阻塞队列中线程的个数
                Executors.defaultThreadFactory(),//线程工厂
                new ThreadPoolExecutor.AbortPolicy());//拒绝所有不在线程池及阻塞队列中的线程任务,并报错

        for (int i = 1; i < 7; i++) {
            final int count = i;
            threadPool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName() + ":顾客 " + count);
                }
            });
        }

        threadPool.shutdown();
    }
}
运行结果
运行结果
1)AbortPolicy():拒绝所有不在线程池及阻塞队列中的线程任务,并报RejectedExecutionException异常
pool-1-thread-1:顾客 1
pool-1-thread-3:顾客 5
pool-1-thread-2:顾客 2
pool-1-thread-1:顾客 3
pool-1-thread-3:顾客 4
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6d6f6e28 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 2]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
	at com.tan.b_create_threadpool.CreateThreadPool.main(CreateThreadPool.java:64)

2)DiscardPolicy():拒绝所有不在线程池及阻塞队列中的线程任务,不报错
pool-1-thread-1:顾客 1
pool-1-thread-3:顾客 5
pool-1-thread-2:顾客 2
pool-1-thread-1:顾客 3
pool-1-thread-2:顾客 4

3)DiscardOldestPolicy():拒绝所有不在线程池及阻塞队列(除了等待最久的线程任务Oldest)中的线程任务,
  并“随机”选取一个在线程池及阻塞队列中的线程任务移除出去,将等待最久的线程任务Oldest添加进来
pool-1-thread-1:顾客 1
pool-1-thread-3:顾客 5
pool-1-thread-1:顾客 4
pool-1-thread-2:顾客 2
pool-1-thread-3:顾客 6

4)CallerRunsPolicy():拒绝所有不在线程池及阻塞队列中的线程任务,并呼叫其他的线程来处理这些线程任务
main:顾客 6
pool-1-thread-3:顾客 5
pool-1-thread-2:顾客 2
pool-1-thread-1:顾客 1
pool-1-thread-2:顾客 4
pool-1-thread-3:顾客 3

你可能感兴趣的:(Java,进阶,java,开发语言,后端)