Java线程池总结

Java线程池总结

  • 一.什么是线程池?
  • 二.为什么要使用线程池?
  • 三.创建线程池
  • 四.线程池配置参数
  • 五.线程池的流程,拒绝策略与提交方式
    • 5.1线程池流程
    • 5.2线程池拒绝策略
    • 5.3线程池提交方式
  • 六.线程池相关问题

一.什么是线程池?

线程池:就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。

二.为什么要使用线程池?

因为 Java 中创建一个线程,需要调用操作系统内核的 API,操作系统要为线程分配一系列的资源,成本很高,所以线程是一个重量级的对象,应该避免频繁创建和销毁。
使用线程池就能很好地避免频繁创建和销毁
线程池的优势:

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

三.创建线程池

常见的几种线程池类型:

  1. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  public static void main(String[] args) throws Exception {
    	ExecutorService pool = Executors.newCachedThreadPool();//创建线程池
    	
    	for(int i =0;i<10;i++) {
    		Thread.sleep(200);
    		pool.execute(()->{//线程池创建线程
    			for(int s =0;s<10;s++) {
    				System.out.println(Thread.currentThread().getName()+":"+s);
    				try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
    			}
    		});
    	}
	}

结果:
Java线程池总结_第1张图片

  1. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
 public static void main(String[] args) throws Exception {
    	ExecutorService pool = Executors.newFixedThreadPool(2);//创建定长为2线程池
    	
    	for(int i =0;i<10;i++) {
    		Thread.sleep(200);
    		pool.execute(()->{//线程池创建线程
    			for(int s =0;s<10;s++) {
    				System.out.println(Thread.currentThread().getName()+":"+s);
    				try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
    			}
    		});
    	}
	}

结果:

Java线程池总结_第2张图片

  1. newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
 public static void main(String[] args) throws Exception {
    	ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);//创建定长为5线程池
    	int t =0;
    	pool.scheduleAtFixedRate(()->//定时创建线程
    	 System.out.println(Thread.currentThread().getName()+":"+t)
    	, 0, 2, TimeUnit.SECONDS);
    	
	}

结果:
Java线程池总结_第3张图片
4. newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

public static void main(String[] args) throws Exception {
    	ExecutorService pool = Executors.newSingleThreadExecutor();//创建线程池
    	
    	for(int i =0;i<10;i++) {
    		Thread.sleep(200);
    		pool.execute(()->{//线程池创建线程
    			for(int s =0;s<10;s++) {
    				System.out.println(Thread.currentThread().getName()+":"+s);
    				try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
    			}
    		});
    	}
	}

结果:
Java线程池总结_第4张图片

四.线程池配置参数

  1. corePoolSiz:线程池中的核心线程数量,在没有用的时候,也不会被回收。
  2. maximumPool:就是线程池中可以容纳的最大线程的数量
  3. keepAliveTi:线程池中除了核心线程之外的其他的最长可以保留的时间,因为在线程池中,除了核心线程即使在无任务的情况下也不能被清除,其余的都是有存活时间的,意思就是非核心线程可以保留的最长的空闲时间
  4. util:计算时间的一个单位
  5. workQueue:就是等待队列,任务可以储存在任务队列中等待被执行,执行的是FIFIO原则(先进先出)
  6. handler:拒绝策略

五.线程池的流程,拒绝策略与提交方式

5.1线程池流程

Java线程池总结_第5张图片

5.2线程池拒绝策略

当任务队列满了之后,如果还有任务提交过来,会触发拒绝策略

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

5.3线程池提交方式

Java线程池总结_第6张图片

六.线程池相关问题

1.线程池核心线程数的设置?
Java线程池总结_第7张图片
(1)CPU的线程数概念仅仅只针对Intel的CPU才有用,因为它是通过Intel超线程技术来实现的。
(2)如果没有超线程技术,一个CPU核心对应一个线程。 所以,对于AMD的CPU来说,只有核心数的概念,没有线程数的概念。
2.高并发、任务执行时间短的业务怎样使用线程池?
高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
3.并发不高、任务执行时间长的业务怎样使用线程池?
假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务。
假如是业务时间长集中在计算操作上,也就是计算密集型任务,线程池中的线程数设置得少一些,减少线程上下文的切换

你可能感兴趣的:(java,java,多线程,线程池)