ThreadPoolExecutor中的任务提交和线程池中的线程复用

execute()方法

execute()传一个Runnable接口,但是我们调用的时候传的是一个实现了Runnable接口的类。多态特性由多态可知,子类对象赋给父类对象时其子类的run方法就传给了父类对象的run方法

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        
        int c = ctl.get();
        //如果当前线程数小于,coresize,那么我们就要生成一个新的Worker
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        
        //如果当前线程数大于coresize,则放到阻塞队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //特殊的线程池,cached
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }

1)线程池有一个预热功能,当线程数小于coresize时,此时addWorker中会生成新的Worker,Worker的构造函数如下

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            //传来的Runnable接口
            this.firstTask = firstTask;
            //通过线程工厂,把this(当前Worker)指针传给Thread,
            //newThread()方法的参数是Runnable接口,Worker实现了Runnable接口,因此把Worker的run方法传过去了,多态的用法
            this.thread = getThreadFactory().newThread(this);
        }

2)当addWorker添加成功是,就会调用Worker对象中的thread属性的start()方法

	    w = new Worker(firstTask);
	    final Thread t = w.thread;
	    t.start();

3)此时,start方法会调用worker的run方法,即runWorker()方法

 		w.firstTask = null;
	    w.unlock(); // allow interrupts
	    boolean completedAbruptly = true;
	    try {
	      while (task != null || (task = getTask()) != null) {
	            ....
	            }

当task不为空,即说明有任务过来
当task为空,task=getTask()不为空,说明没有任务过来,从阻塞队列中能获取到任务
getTask方法

	        for (;;) {
	            ....
	             Runnable r = timed ?
	                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
	                    workQueue.take();
	            if (r != null)
	                    return r;
	            ....
	        }

线程池总结
1)当刚提交任务的时候,如果小于coresize,就生成新的Worker()即Thread。
2)如果提交时,大于了coresize,那么就放入WorkQueue的阻塞队列中。当阻塞队列有元素时,那么之前生成的线程就可以进行复用了

线程复用情形
假设有一个线程池的coresize为5,那么假设5个线程工作状态,此时有一个任务来了。则5个线程工作完成后,它们中只有一个线程能够获取这个任务,其余线程由于在getTask()中没有抢到任务,因此getTask就会一直处于自旋且不会返回。这样就完成了线程的复用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了避免线程池线程阻塞,我们可以采用以下两种方法: 1.合理设置线程池的大小。线程池线程的数量应该根据任务的类型和系统的负载来设置。如果线程池线程数量过多,会导致线程之间的竞争,从而降低整体效率。如果线程池线程数量过少,会导致任务等待线程的时间过长,从而影响整体效率。因此,我们需要根据实际情况来设置线程池的大小。 2.使用线程池线程复用原理。线程池线程是可以复用的,当一个线程执行完任务后,它并不会立即销毁,而是会等待下一个任务的到来。因此,我们可以通过复用线程来避免线程阻塞。具体来说,我们可以将任务分为两类:CPU密集型任务和IO密集型任务。对于CPU密集型任务,我们可以设置线程池的大小为CPU核心数的两倍;对于IO密集型任务,我们可以设置线程池的大小为CPU核心数的四倍。 ```python import concurrent.futures import time # 定义一个IO密集型任务 def io_task(n): time.sleep(1) return n * n # 定义一个CPU密集型任务 def cpu_task(n): for i in range(10000000): n += 1 return n # 创建线程池 with concurrent.futures.ThreadPoolExecutor(max_workers=8) as executor: # 提交IO密集型任务 io_futures = [executor.submit(io_task, i) for i in range(8)] # 提交CPU密集型任务 cpu_futures = [executor.submit(cpu_task, i) for i in range(8)] # 获取IO密集型任务的结果 io_results = [f.result() for f in io_futures] print(io_results) # 获取CPU密集型任务的结果 cpu_results = [f.result() for f in cpu_futures] print(cpu_results) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值