线程池

1.线程池

对于互联网应用来说,如果每个用户的请求都创建一个线程,那会非常得多,服务器也是难于承受, 再说了,众多的线程去竞争CPU,不断切换,也会让CPU调度不堪重负,很多线程将不得不等待。所以前辈们的思路就是
(1)用少量的线程 (2) 让线程保持忙碌
就是说只创建一定数量的线程,让这些线程去处理所有的任务,任务执行完了以后,线程并不结束,而是回到线程池中去,等待接受下一个任务。
当线程池的线程刚创建时,让他们进入阻塞状态:等待某个任务的到来。 如果任务来了,唤醒其中一个线程,让它拿到任务去执行即可。
那么如何进入阻塞状态呢?
就是一个线程调用它的take()方法取数据时, 如果这个Queue中没有数据,该线程会阻塞;同样,一个线程调用它的put方法放数据时,如果Queue满了, 也会阻塞。看来线程池中每个线程的run()方法中,要设置一个循环,每次都尝试从BlockingQueue中获取任务,如果Queue是空的,就阻塞等待, 如果有任务来了,就会通知到线程池的某一个线程去处理,处理完了以后,依然试图从BlockingQueue中获取任务,就这么依次循环下去。

在这里插入图片描述

2.线程池创建

1.可以手动创建线程池
ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象:
ExecutorService提供了管理Eecutor生命周期的方法,ExecutorService的生命周期包括了:运行 关闭和终止三种状态。
ExecutorService在初始化创建时处于运行状态。
shutdown方法等待提交的任务执行完成并不再接受新任务,在完成全部提交的任务后关闭
shutdownNow方法将强制终止所有运行中的任务并不再允许提交新任务

 ExecutorService service = new ThreadPoolExecutor(corePoolSize :10,maxPoolSize: 10, keepAliveTime :0,timeUnit: TimeUnit.SECONDS,
                BlockingQueue: new LinkedBlockingQueue<>());
 service.submit(new Runnable(){
                @Override
                public void run() {
                    // 把io相关的操作放在线程内执行,让每个线程处理一个io操作,避免io阻塞
                    try {
                        handle(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

corePoolSize:代表线程池核心线程数如果运行的线程少于corePoolSize,则创建新线程来执行新任务,即使线程池中的其他线程是空闲的
maxPoolSize:最大线程数
keepAliveTime:保持时间
TimeUnit:时间单位
BlockingQueue:阻塞队列,与线程池的大小有关(有界new ArrayBlockingQueue<>(10),无界new LinkedBlockingQueue<>())
1) 刚开始没有线程,来任务创建线程,来5个任务创建5个线程,当任务数超过核心线程数,将任务放到阻塞队列里排队运行,当超过有界队列数时(队列满了),使用最大线程数,超过最大线程数时就拒绝任务。
(核心线程数+救急线程数(队列满时新创建的线程)<=最大线程数)
2)保持时间:任务高峰期过了,线程闲下来,把闲的线程从线程池中回收,但不会少于核心线程数。(不回收核心线程数)
(闲暇时间>保持时间,就回收)
3)核心线程数为0,表示闲暇后把所有的线程都回收。
4)保持时间为0:不会创建救急线程
5)当运行的线程数少于corePoolSize时,在有新任务时直接创建新线程来执行任务而无需再进队列
6)当运行的线程数等于或多于corePoolSize,在有新任务添加时则选加入队列,不直接创建线程
7)当队列满时,在有新任务时就创建新线程
2.作为java.util.concurrent包的一部分,直接调用即可。
Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),提供了一系列静态工厂方法用于创建各种线程池
(1)获取线程池对象

 ExecutorService executorService = Executors.newFixedThreadPool(10);
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        handle(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            executorService.shutdown();//关闭线程池

(2)获取一个指定数量线程对象的线程池

public class MyCallable implements Callable<Integer> {
    int len;
    public MyCallable(int i) {
        len=i;
    }
    @Override
    public Integer call() throws Exception {
        //做累加操作
        int sum=0;
        for (int i = 1; i <= len; i++) {
            sum+=i;
        }
        return sum;
    }
}
 public static void main(String[] args) throws ExecutionException, InterruptedException {
        //获取一个有指定数量线程对象的线程池
        ExecutorService service = Executors.newFixedThreadPool(3);
        //往线程池里面提交任务
        Future<Integer> submit = service.submit(new MyCallable(10));
        Future<Integer> submit1 = service.submit(new MyCallable(100));
        Future<Integer> submit2 = service.submit(new MyCallable(1000));
        //获取Callable任务执行完之后的返回结果 Future 里面有一个get()方法可以获取返回的结果
        System.out.println(submit.get());
        System.out.println(submit1.get());
        System.out.println(submit2.get());
        //关闭线程池
        service.shutdown();
    }

Callable 这个任务接口,执行完之后会有返回值 跟线程池配合使用
获取Callable任务执行完之后的返回结果 Future 里面有一个get()方法可以获取返回的结果
Runnable 这个任务接口 执行完之后没有返回值

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值