三、线程池知识点整理笔记

297 阅读3分钟

5、线程池知识点整理

1)、线程池类型:
	newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,
	                     可灵活回收空闲线程,若无可回收,则新建线程;
	newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,
	                    超出的线程会在队列中等待;
	newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行;
	newSingleThreadExecutor:创建一个单线程化的线程池,它只会用
	                         唯一的工作线程来执行任务,保证所有任务按照
	                         指定顺序(FIFO, LIFO, 优先级)执行。
	newSingleThreadScheduledExecutor:只有一个线程,用来调度执行将来的任务。
	
2)、线程池示例参数:
	new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime, 
	TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
	a)、第一个参数:corePoolSize,核心线程数量,
	b)、第二个参数:int maximumPoolSize,线程池最大线程数
	c)、第三个参数:long keepAliveTime,表示线程没有任务执行时最多保持多久时间会终止
	d)、第四个参数:TimeUnit unit,参数keepAliveTime的时间单位,有7种取值
	e)、第五个参数:workQueue,一个阻塞队列,通过execute方法提交的runnable对象
	               会存储在该队列中
	其中阻塞队列分为以下几种:
		(1)、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务
		(2)、LinkedBlockingQueue:基于链表结构的阻塞队列,按FIFO排序任务,吞
		 吐量通常要高于ArrayBlockingQuene;是无界的,可以不指定队列的大小,但是
		 默认是Integer.MAX_VALU。
		(3)、SynchronousQueue:一个不存储元素的阻塞队列,每个插入操作必须等到
		另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于(2);
		(4)、priorityBlockingQueue:具有优先级的无界阻塞队列;
	
3)、线程池的饱和策略
	当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,
	线程池提供了4种策略:
	a)、ThreadPoolExcutor.AbortPolicy()——直接抛出异常,默认操作;
	b)、ThreadPoolExcutor.CallerRunsPolicy()——只用调用者所在线程来运行任务;
	c)、ThreadPoolExcutor.DiscardOldersPolicy()——丢弃队列里最近的一个任务,
	    并执行当前任务;
	d)、ThreadPoolExcutor.DiscardPolicy()——不处理,直接丢掉;
	    也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略。
	
4)、执行流程:
	执行excute()方法之后
	a)、判断线程池存在核心线程的数量与corePoolSize的大小,
	    若小于corePoolSize,则调用addWorker函数创建新线程;
	    否则执行b;
	b)、判断等待队列是否已满,若未满,则加入队列中;否则执行c;
	c)、判断线程池是否已满,若未满,则创建线程执行任务;否则执行d;
	d)、按照饱和策略,处理任务
部分源码(核心在addWorker):
        public void execute(Runnable command) {
            if (command == null)
                throw new NullPointerException();
            int c = ctl.get();
            if (workerCountOf(c) < corePoolSize) {
                if (addWorker(command, true))
                   return;
                c = ctl.get();
                }
            if (isRunning(c) && workQueue.offer(command)) {
                int recheck = ctl.get();
                if (! isRunning(recheck) && remove(command))
                    reject(command);
                else if (workerCountOf(recheck) == 0)
                    addWorker(null, false);
                }
            else if (!addWorker(command, false))
                reject(command);
            }

流程图(网上找的):