Java线程池小结

目录

一.什么是线程池

二.线程池的好处是什么

 三.四种基本线程池及其使用

newCachedThreadPool

 newFixedThreadPool

newScheduledThreadPool 

newSingleThreadExecutor

线程池的四种拒绝策略

选择一:AbortPolicy

选择二:CallerRunsPolicy

选择三:DiscardPolicy

选择四:DiscardOldestPolicy

模拟实现简单的一个线程池


一.什么是线程池

简单来说,就是在系统的内存里面开辟一个容器用来存放线程

一旦线程结束之后,系统不会立刻回收销毁该线程,而是等他继续在容器里面

如果有其他任务需要调用该线程,就直接从容器里面拿出来

从而不必重新new和销毁线程

二.线程池的好处是什么

降低资源销毁:通过重复利用已经创建的线程,降低线程创建和销毁造成的消耗。
提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。
防止服务器过载:形成内存溢出,或者CPU耗尽。.
提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗资源,还会降低系统的稳定性,使用线程池可以进行统一的分配、调优和监控。

 三.四种基本线程池及其使用

newCachedThreadPool

创建一个无最大容量的线程池

如果当前池子里的线程超过正在处理的线程数量,可回收空闲线程,如果池内没有该线程,则向池中放入一个新线程

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class mode9 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            int j = i;
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName() + "," + j);
            });

        }
    }
}

 newFixedThreadPool

创建一个有容量的线程池

可控制线程最大并发数,超出的线程会在队列中等待

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class demo10 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 3; i++) {
            int j = i;
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+j);
            });
        }
    }
}

newScheduledThreadPool 

创建一个有容量,并且能控制运行时间的线程池

public class demo11 {
    public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 5; i++) {
            int j = i;
            pool.schedule(()->{
                System.out.println(Thread.currentThread().getName()+j);
            },3,TimeUnit.SECONDS);
        }
    }
}

newSingleThreadExecutor

采取优先级方式,从始至终都只有一个线程在运行(效率降低,安全性提升)

和第一个newCachedThreadPool基本上没什么区别,就是在他的基础上限定了只能同时运行一个罢了

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class demo12 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 5; i++) {
            int j = i;
            pool.execute(()->{
                System.out.println(Thread.currentThread().getName()+j);
            });
        }
    }
}

线程池的四种拒绝策略

1.AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满,默认该方式。
2.CallerRunsPolicy:直接调用execute来执行当前任务。
3.DiscardPolicy:丢弃任务,但是不抛出异常。
4.DiscardOldestPolicy:抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。先从任务队列中弹出最先加入的任务,空出一个位置,然后再次执行execute方法把任务加入队列。

 对于上面四种方式我们来举例

假如说,你正在打游戏,这个时候你的老板突然打电话来让你去工作,你就有如下四种选择

选择一:AbortPolicy

哇的一声,哭出来,表示日子过不下去了,打游戏都不让我打了

这个时候,因为你在哭,不仅游戏没有继续打,而且老板让你去工作这件事也没执行

两件事都同时停下了(报错)

选择二:CallerRunsPolicy

直接回怼老板:自己开的公司,就该自己去做事情,别麻烦我

老板听到这句话,只好创建一个属于老板自己的线程,自己去开始工作

(注意,这里老板创建了一个属于自己的进程)

(也就是说发起者创建了一个属于自己的进程来执行,而不要你执行了)

选择三:DiscardPolicy

你无视了老板的电话,继续打游戏

这样老板也不知道你什么情况

你任然能继续你手头的工作而且不会报错

选择四:DiscardOldestPolicy

你查看了一下时间表

放假是周六和周日

今天是周六

于是你选择抛弃周日

最后的周日的任务改为执行老板的工作

模拟实现简单的一个线程池

class MyThreadPool {
//定义一个阻塞队列用来存储线程
    private  BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    class Worker extends Thread {
//获取这个阻塞队列
        private BlockingQueue<Runnable> queue;
//初始化
        public Worker(BlockingQueue<Runnable> queue) {
            this.queue = queue;
        }
//重写执行方法
        @Override
        public void run() {
           while (true) {
               try {
//从队列中取线程开始执行
                   Runnable runnable = queue.take();
                   runnable.run();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        }
    }
//用链表来对阻塞队列中的线程进行链接,让其能知道执行完毕后下一个执行谁
    private List<Worker> workers = new ArrayList<>();

//这个是指定线程池的大小
    public MyThreadPool(int threadNums) {
        for (int i = 0; i < threadNums; i++) {
            Worker worker = new Worker(this.queue);
            worker.start();
            this.workers.add(worker);
        }
    }
//实现submit,相当于execute但两者还是有区别,有兴趣的同学自己可以查查资料
    public void submit(Runnable runnable) {
        try {
            this.queue.put(runnable);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值