多线程与并发 | 线程池

多线程与并发 | 线程池

1. 线程池的优势

  • 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗
  • 提高系统响应速度,当有任务到达时,通过复用已存在线程,无需等待新线程的创建便能立即执行
  • 方便线程并发数的管控,因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换
  • 提供更强大的功能,比如延时定时线程池

2. 线程池的主要参数

public ThreadPoolExecutor(
	int corePoolSize,
	int maximumPoolSize,
	long keepAliveTime,
	TimeUnit unit,
	BlockingQueue<Runnable> workQueue,
	ThreadFactory threadFactory,
	RejectedExecutionHandler handler)

2-1. corePoolSize

当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务.可以通过prestartCoreThread()方法来提前启动线程池中的核心线程

2-2. maximumPoolSize

线程池所允许的最大线程个数.当队列满了,且已创建的线程数小于maximumPoolSize,则线程池会创建新的线程来执行任务

2-3. keepAliveTime

当线程池中线程数大于核心线程数时,线程的空闲时间如果超过线程存活时间,则这个线程就会被销毁,知道线程池中的线程数小于等于核心线程数

2-4. workQueue等待队列

用于传输和保存等待执行任务的阻塞队列

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • SynchronizedQueue

2-5. threadFactory

用于创建新线程

2-6. handler拒绝策略

当线程池和队列都满了,再加入线程会执行此策略

  • AbortPolicy直接抛出异常,提示线程已满(默认拒绝策略)
  • DisCardPolicy不执行新任务,也不抛出异常
  • DisCardOldSetPolicy将消息队列中的第一个任务替换为当前新任务
  • CallerRunsPolicy直接调用execute来执行当前任务

3. execute和submit

  • public void execute(Runnable command)
    execute没有返回值
  • submit()更通用一些,可以传入Runnable和Callable
    submit(Runnable task,T result)
    submit(Runnable task) 没有返回值,相当于execute(task)
    submit(Callable task)返回future,通过future.get(),阻塞直到获取返回值

4. 如何配置线程池

  • CPU密集型任务
    一般线程数为CPU核心数 + 1 . 因为CPU密集型任务使得CPU使用率很高,若开过多的线程数,会造成CPU过度切换
  • IO密集型任务
    一般为2 * CPU核心数. IO密集型任务CPU使用率不高,因此可以让CPU在等待IO的时候有其他线程去处理别的任务,充分利用CPU时间
  • 混合型任务
    将任务分成IO密集型和CPU密集型任务,然后分别用不同的线程池去处理

5. java中提供的线程池

newCachedThreadPool,newFixedThreadPool,newSchduledThreadPool,newSingleThreadExecutor

方法 core max keepAliveTime workQueue
newCachedThreadPool 0 Integer.MAX_VALUE 60s SynchronousQueue
newFixedThreadPool nThreads nThreads 0 LinkedBlockingQueue(Integer.MAX_VALUE)
newSingleThreadExecutor 1 1 0 LinkedBlockingQueue(Integer.MAX_VALUE)
newScheduledThreadPool corePoolSize Integer.MAX_VALUE 0 DelayedWorkQueue
上一篇:SQLmap注入练习——dvwa


下一篇:sqli-labs Less11-Less16