线程池是啥有啥用,怎么用,如何自己实现一个

目录

一、线程池是啥,有啥用

二、线程池怎么用 

1.构造方法 

2.如何使用Java的线程池  

三、简单实现一个线程池


假设我是一个(好看+有才华) 的妹子,那么我就会有很多追求者,这些也叫备胎们,我们若把他们放到一个地方,那就叫“备胎池”。同理,线程就叫“线程池”。

一、线程池是啥,有啥用

频繁的创建销毁线程开销太大,所以我们会先创建一些线程放着,要用的时候直接拿就行了,这些线程都放一块地方,用完之后再放回这个地方,那么我们管这个地方叫“线程池”。

 所以:线程池最⼤的好处就是减少每次启动、销毁线程的损耗。

 

那么为什么线程池的效率更高,开销更小呢? 

 那么就得谈谈:用户态和内核态

比如说:

1)在银行你要办业务,可能会需要身份证或者户口本复印件,这时候,你如果没带,那么银行可能会有复印机。

2)那么你有2种选择:第一种是去柜台让柜员帮你,第二种是自己去大厅的复印机复印。

3)内核态:如果让柜员帮你去后台复印,可能没这么快,柜员也许要帮别人也复印,也可能去摸鱼,也可能去上个厕所。我们知道操作系统是由内核和软件组成,有很多软件都需要内核管理,可能会没那么及时。

4)用户态:如果你是自己去大厅复印,自给自足,非常的快。

5)而我们的线程池就是用户态,自己创建线程是内核态,所以效率会比线程池低。

二、线程池怎么用 

 我们有专门的类表示线程池:ThreadPoolExecutor

1.构造方法 

下面是它的构造方法,最主要的是第4个最为全面,其他三个都是从第4个演化出来的。

 我们分析一下这个线程池的参数:

  • corePoolSize:正式员⼯的数量. (正式员⼯, ⼀旦录⽤, 永不辞退)
  • maximumPoolSize: 正式员⼯ + 临时⼯的数⽬. (临时⼯: ⼀段时间不⼲活, 就被辞退)
  • keepAliveTime: 临时⼯允许的空闲时间
  • unit: keepaliveTime 的时间单位, 是秒, 分钟, 还是其他值
  • workQueue: 传递任务的阻塞队列
  • threadFactory: 创建线程的⼯⼚, 参与具体的创建线程⼯作,通过不同线程⼯⼚创建出的线程相当于 对⼀些属性进⾏了不同的初始化设置
  • RejectedExecutionHandler: 拒绝策略, 如果任务量超出公司的负荷了接下来怎么处理 
    1. AbortPolicy(): 超过负荷, 直接抛出异常          
    2. CallerRunsPolicy(): 调⽤者负责处理多出来的任务     
    3. DiscardOldestPolicy(): 丢弃队列中最⽼的任务
    4. DiscardPolicy(): 丢弃新来的任务  

1)corePoolSize和maximumPoolSize中,如果核心线程数是M个,在使用的过程中发现不够用,会自动扩容多M个,直至最大线程数max个。

 2)keepAliveTime和unit是姐妹,一起用的,就是实习生(非核心线程)太久没活干了,就会裁掉它,怎么样才算太久呢?就需要你自己设置一个时间

3)workQueue是我们需要传进去的堵塞队列,线程池就是一个生产者消费者模型,程序员把任务submit放进线程池中。这个队列可以自己设计容量和类型。

4)线程工厂,是为了弥补构造方法的不足,比如假设我在二维中需要表示一个点,我有2种方法,第一种是横纵坐标,第二种是用极坐标,

但是这样的话重载就失效了,因为名字参数什么的啥都一样啊,构成不了重载。

而是需要工厂设计模式解决,如上图。

5)拒绝策略(重点):当线程池的要执行的任务满了,它就会进行堵塞。但是有时候这未必是件好事。比如说你女神直接拒绝你,比起干耗着你好,这样你就能开启新的生活了。

假设线程池是女神,你是任务,但是备胎太多了忙不过来。

第一个就是女神拒绝了你,你崩溃了,其他备胎也崩溃了(没想到女神有这么多备胎);

第二个女神不想你追她,让你去追其他小姐姐,但是女神依旧和备胎们约会;

第三个是把追的最久的备胎扔掉,没新鲜感了,和最新追我的约会;

第四个是把最新的备胎踢掉,是个念旧的女神,就当一切没有发生,继续和之前的备胎们约会。

2.如何使用Java的线程池  

虽然ThreadPoolExecutor固然强大,但是参数太多,用起来确实麻烦,所以Java标准库中有更方便的:Executor提供了一些工厂方法,比如:

接受线程池的类型:ExecutorService

创建便捷线程池的方法:newFixedThreadPool(),把核心线程数和最大线程数设置成一样,不会自动扩容

添加任务到线程池执行:submit() 

public static void main(String[] args) throws InterruptedException {
        ExecutorService service=Executors.newFixedThreadPool(4);
        for(int i=0;i<100;i++){
            int id=i;
        service.submit(()->{
            Thread current=Thread.currentThread();
            System.out.println("hello world "+id+ " "+current.getName());
        });

        }
        Thread.sleep(2000);
        service.shutdown();
        System.out.println("程序结束");
    }

三、简单实现一个线程池

需要如下条件:

一个堵塞队列queue,来装要执行的任务,通过take取任务。

线程池类,来用for循环放线程(相当于线程池),这个类有submit()方法用queue队列中用put就能放进去执行这些线程中。

(由于拒绝策略太麻烦了,这里没有写出来,感兴趣的可以自行写一下)

class MyThreadPool {
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);

    //创造线程
    public MyThreadPool(int n) {
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                while (true) {
                    try {
                        Runnable runnable=queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
        }
    }

    //创建任务
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}

public class demo15 {
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool myThreadPool=new MyThreadPool(4);
        for(int i=0;i<1000;i++){
            int id=i;
            myThreadPool.submit(()->{
                System.out.println("执行任务 "+id+" "+Thread.currentThread().getName());
            });
        }
    }

}
  •  核⼼操作为 submit,将任务加⼊线程池中
  •  使⽤ Worker 类描述⼀个⼯作线程。使⽤ Runnable 描述⼀个任务.
  •  使⽤⼀个 BlockingQueue 组织所有的任务
  •  每个 worker 线程要做的事情:不停的从 BlockingQueue 中取任务并执⾏
  •  指定⼀下线程池中的最⼤线程数 maxWorkerCount;当当前线程数超过这个最⼤值时,就不再新增线程了
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值