精华内容
下载资源
问答
  • 创建线程池有哪几种方式

    千次阅读 2020-05-04 22:15:27
    创建线程池有哪几种方式一、Executors二、ThreadPoolExecutor 一、Executors Executors是一个线程相关的工具类。主要提供了以下几种创建线程池的方法: index method corePoolSize maximumPoolSize ...

    一、Executors

    Executors是一个线程相关的工具类。主要提供了以下几种创建线程池的方法:

    index method corePoolSize maximumPoolSize keepAliveTime unit workQueue
    1 newCachedThreadPool 0 Integer.MAX_VALUE 60L TimeUnit.SECONDS SynchronousQueue
    2 newFixedThreadPool 自定义 与corePoolSize相同 0L TimeUnit.MILLISECONDS LinkedBlockingQueue
    3 newSingleThreadExecutor 1 1 0L TimeUnit.MILLISECONDS LinkedBlockingQueue
    4 newScheduledThreadPool 自定义 Integer.MAX_VALUE 0 NANOSECONDS DelayedWorkQueue
    5 newSingleThreadScheduledExecutor 1 Integer.MAX_VALUE 0 NANOSECONDS DelayedWorkQueue

    第1,4,5种:线程最大数量是Integer.MAX_VALUE,当执行大量耗时任务时,容易造成堆外内存溢出
    第2,3种:使用的的阻塞队列为无边界队列,当任务量过大时,可能会导致内存溢出

    注意: 在java8中新添加了newWorkStealingPool

    二、ThreadPoolExecutor

    ThreadPoolExecutor(int corePoolSize, //核心线程数量
                       int maximumPoolSize, // 最大线程数量
                       long keepAliveTime, // 存活时间 
                       TimeUnit unit, // 时间单位
                       BlockingQueue<Runnable> workQueue, //阻塞队列
                       ThreadFactory threadFactory) // 拒绝策略
    

    注意: 有多于corePoolSize但小于maximumPoolSize线程正在运行,则仅当队列已满时才会创建新线程

    在这里插入图片描述

    展开全文
  • JDK1.8 创建线程池有哪几种方式?

    万次阅读 2019-05-16 12:48:53
    JDK1.8创建线程池有哪几种方式? newFixedThreadPool 定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程 测试代码...

    JDK1.8 创建线程池有哪几种方式?

    • newFixedThreadPool

    定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程

    测试代码:

    public class TestThreadPool {
    
    	//定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
    	static ExecutorService fixedExecutor = Executors.newFixedThreadPool(3);
    	
    	
    	public static void main(String[] args) {
    		testFixedExecutor();
    	}
    	
    	//测试定长线程池,线程池的容量为3,提交6个任务,根据打印结果可以看出先执行前3个任务,3个任务结束后再执行后面的任务
    	private static void testFixedExecutor() {
    		for (int i = 0; i < 6; i++) {
    			final int index = i;
    			fixedExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		fixedExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-2 index:1
    pool-1-thread-3 index:2
    4秒后...
    pool-1-thread-3 index:5
    pool-1-thread-1 index:3
    pool-1-thread-2 index:4

     

     

    • newCachedThreadPool

    可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制

    测试代码:  

    public class TestThreadPool {
    
    	//可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
    	static ExecutorService cachedExecutor = Executors.newCachedThreadPool();
    	
    	
    	public static void main(String[] args) {
    		testCachedExecutor();
    	}
    	
    	//测试可缓存线程池
    	private static void testCachedExecutor() {
    		for (int i = 0; i < 6; i++) {
    			final int index = i;
    			cachedExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		cachedExecutor.shutdown();
    	}
    	
    }
    

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-6 index:5
    pool-1-thread-5 index:4
    pool-1-thread-4 index:3
    pool-1-thread-3 index:2
    pool-1-thread-2 index:1
    4秒后...
    

     

     

    • newScheduledThreadPool

    定长线程池,可执行周期性的任务

    测试代码:

    public class TestThreadPool {
    
    	//定长线程池,可执行周期性的任务
    	static ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3);
    	
    	
    	public static void main(String[] args) {
    		testScheduledExecutor();
    	}
    	
    	//测试定长、可周期执行的线程池
    	private static void testScheduledExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
    				public void run() {
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			}, 0, 3, TimeUnit.SECONDS);
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		scheduledExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-2 index:1
    pool-1-thread-3 index:2
    pool-1-thread-1 index:0
    pool-1-thread-3 index:1
    pool-1-thread-1 index:2
    4秒后...
    

     

     

    • newSingleThreadExecutor

    单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行

    测试代码:

    public class TestThreadPool {
    	
    	//单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
    	static ExecutorService singleExecutor = Executors.newSingleThreadExecutor();
    	
    	
    	public static void main(String[] args) {
    		testSingleExecutor();
    	}
    	
    	//测试单线程的线程池
    	private static void testSingleExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			singleExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		singleExecutor.shutdown();
    	}
    	
    }
    

    打印结果:

    pool-1-thread-1 index:0
    4秒后...
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2

     

     

    • newSingleThreadScheduledExecutor

    单线程可执行周期性任务的线程池

    测试代码:

    public class TestThreadPool {
    	
    	//单线程可执行周期性任务的线程池
    	static ScheduledExecutorService singleScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
    	
    	
    	public static void main(String[] args) {
    		testSingleScheduledExecutor();
    	}
    	
    	//测试单线程可周期执行的线程池
    	private static void testSingleScheduledExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			singleScheduledExecutor.scheduleAtFixedRate(new Runnable() {
    				public void run() {
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			}, 0, 3, TimeUnit.SECONDS);
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		singleScheduledExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2
    pool-1-thread-1 index:0
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2
    4秒后...
    

     

     

    • newWorkStealingPool

    任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。

    线程池中有多个线程队列,有的线程队列中有大量的比较耗时的任务堆积,而有的线程队列却是空的,就存在有的线程处于饥饿状态,当一个线程处于饥饿状态时,它就会去其它的线程队列中窃取任务。解决饥饿导致的效率问题。

    默认创建的并行 level 是 CPU 的核数。主线程结束,即使线程池有任务也会立即停止。

    测试代码:

    public class TestThreadPool {
    
    	//任务窃取线程池
    	static ExecutorService workStealingExecutor = Executors.newWorkStealingPool();
    	
    	public static void main(String[] args) {
    		testWorkStealingExecutor();
    	}
    	
    	//测试任务窃取线程池
    	private static void testWorkStealingExecutor() {
    		for (int i = 0; i < 10; i++) {//本机 CPU 8核,这里创建10个任务进行测试
    			final int index = i;
    			workStealingExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);//这里主线程不休眠,不会有打印输出
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    //		workStealingExecutor.shutdown();
    	}
    	
    }

    打印结果如下,index:8,index:9并未打印出:

    ForkJoinPool-1-worker-1 index:0
    ForkJoinPool-1-worker-7 index:6
    ForkJoinPool-1-worker-5 index:4
    ForkJoinPool-1-worker-3 index:2
    ForkJoinPool-1-worker-4 index:3
    ForkJoinPool-1-worker-2 index:1
    ForkJoinPool-1-worker-0 index:7
    ForkJoinPool-1-worker-6 index:5
    4秒后...
    

     


    【Java面试题与答案】整理推荐

     

    展开全文
  • 创建线程池有哪几种方式? Executors.newFixedThreadPool(4); 实际实现 new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) 固定线程数为4 ...

    创建线程池有哪几种方式?

    • Executors.newFixedThreadPool(4);

      • 实际实现 new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())
      • 固定线程数为4 同时超出线程数将放在 LinkedBlockingQueue 中 默认是Integer.MAX_VALUE 可能阻塞过多可能出现 oom
    • Executors.newSingleThreadExecutor();

      • 实际实现 new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()))
      • 固定线程数为1 和newFixedThreadPool 区别包裹了 FinalizableDelegatedExecutorService 这样就无法转成ThreadPoolExecutor 也就不能修改线程数了
    • Executors.newScheduledThreadPool(4);

      • 实际实现 new ScheduledThreadPoolExecutor(corePoolSize);
      • 固定线程 返回可定时 可延时 处理的 ScheduledThreadPoolExecutor

      ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService

    • Executors.newCachedThreadPool();

      • 实际实现 new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
      • 固定线程数为0 可以无限增长Integer.MAX_VALUE 会有oom
    • Executors.newWorkStealingPool();

      • 实际实现 new ForkJoinPool (Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) java.util.concurrent.ForkJoinPool
      • 适用于耗时长的线程任务
    • 推荐使用 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

      • 几个参数
        • 核心线程池数

          • 如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;
          • 如果线程池中的线程数量大于等于 corePoolSize 且小于 maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务;
          • 如果设置的corePoolSize 和 maximumPoolSize相同,则创建的线程池的大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理;
          • 如果运行的线程数量大于等于maximumPoolSize,这时如果workQueue已经满了,则通过handler所指定的策略来处理任务;
          • 所以,任务提交时,判断的顺序为 corePoolSize –> workQueue –> maximumPoolSize。
        • 最大线程数

        • 空任务回收时长

        • 空任务回收时长单位

        • 超出线程池的任务阻塞队列

          • 直接切换:这种方式常用的队列是SynchronousQueue
          • 使用无界队列:一般使用基于链表的阻塞队列LinkedBlockingQueue。如果使用这种方式,那么线程池中能够创建的最大线程数就是corePoolSize,而maximumPoolSize就不会起作用了(后面也会说到)。当线程池中所有的核心线程都是RUNNING状态时,这时一个新的任务提交就会放入等待队列中
          • 使用有界队列:一般使用ArrayBlockingQueue。使用该方式可以将线程池的最大线程数量限制为maximumPoolSize,这样能够降低资源的消耗,但同时这种方式也使得线程池对线程的调度变得更困难,因为线程池和队列的容量都是有限的值,所以要想使线程池处理任务的吞吐率达到一个相对合理的范围,又想使线程调度相对简单,并且还要尽可能的降低线程池对资源的消耗,就需要合理的设置这两个数量
        • 线程工厂

          • 常用 默认Executors.defaultThreadFactory() 这种会设定默认线程名 和 普通优先级 和 非守护线程
          • 推荐 重写成带线程池名工厂 方便定位问题
        • 超出策略

          • AbortPolicy:直接抛出异常,这是默认策略;
          • CallerRunsPolicy:用调用者所在的线程来执行任务;
          • DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
          • DiscardPolicy:直接丢弃任务;

    线程池流程

    线程池都有哪些状态?

    源码中状态定义

    
        // runState is stored in the high-order bits
        private static final int RUNNING    = -1 << COUNT_BITS;
        private static final int SHUTDOWN   =  0 << COUNT_BITS;
        private static final int STOP       =  1 << COUNT_BITS;
        private static final int TIDYING    =  2 << COUNT_BITS;
        private static final int TERMINATED =  3 << COUNT_BITS;
    
    

    状态变换

    展开全文
  • 线程池创建有方式,最核心的是最后一: newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会一个任务处于活动状态,...

    线程池创建有七种方式,最核心的是最后一种:

    1. newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
    2. newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列;
    3. newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;
    4. newSingleThreadScheduledExecutor():创建单线程池,返回 ScheduledExecutorService,可以进行定时或周期性的工作调度;
    5. newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
    6. newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
    7. ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor的封装。
    展开全文
  • 创建java线程池有以下几种方式: 1.newSigleThreadExecutor 创建一个单线程线程池。这个线程池只有一个线程在工作,也就相当于单线程串行执行所有任务,如果这个唯一线程因为异常结束,那么就会有一个新的线程去...
  • 创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。 newCachedThreadPool() 创建一个...
  • 1.newFixedThreadPool(int nThreads):创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程...
  • Java四种线程池 :Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService。①. newFixedThreadPool(int nThreads)创建一个...
  • 一、并发类库中的线程池 线程是不能重复启动的,频繁创建和销毁...通常开发者都是利用Executors中的线程池创建方法创建线程池。通过指定不同的参数就可以创建出不同类型的线程池。 Executors提供的线程池创建配置...
  • 通常开发者都是利用 Executors 提供的通用线程池...newCachedThreadPool(),它是一用来处理大量短时间工作任务的线程池,具有个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程...
  • 对于这两,也分别启动线程的方式: 1)继承Thread类,implements Runnable接口 2)实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现返回结果的线程 ...
  • 既然创建或销毁线程存在一定的开销,所以利用线程池技术来提高系统资源利用效率,并简化线程管理,已经是非常成熟的选择。...Executors目前提供了5不同的线程池创建配置: newCachedThreadPool(),它是一用...
  • 一、并发类库中的线程池线程是不能重复启动的,频繁创建和...通常开发者都是利用Executors中的线程池创建方法创建线程池。通过指定不同的参数就可以创建出不同类型的线程池。Executors提供的线程池创建配置:newCa...
  • 21.Java并发类库提供的线程池有哪几种?分别有什么特点?  通常开发者都是利用Executors提供的通用线程池创建方法,去创建不同配置的线程池,主要区别在于ExecutorService类型或者不同的初始参数。  Executors...
  • 通常开发者都是利用Executors提供的...newCachedThreadPool(),它是一用来处理大量短时间工作任务的线程池,具有个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如 果线程...
  • newCachedThreadPool(),它是一用来处理大量短时间工作任务的线程池,具有个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存...
  • 今天我要问你的问题是,Java 并发类库提供的线程池有哪几种? 分别有什么特点? 典型回答 通通常开发者都是利用 Executors 提供的通用线程池创建方法,去创建不同配置的线程池,主要区别在于不同的 ...
  • 线程池就是创建若干个可执行的线程放入一个池(容器)中,任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁, 而是仍然在线程池中等待下一个任务。 通过Executors工厂方法创建 通过new ...
  • 有些童鞋一直在使用线程池,但是,对于如何创建线程池仅仅停留在使用Executors工具类的方式,那么,创建线程池究竟存在哪几种方式呢?就让我们一起从创建线程池的源码来深入分析究竟哪些方式可以创建线程池。使用...
  • 根据摩尔定律所说:集成电路上可容纳的晶体管数量每 18 个月翻一番,因此 CPU 上的晶体管数量会越来越多。 但随着时间的推移,集成电路上可...线程池(ThreadPool)是一基于池化思想管理和使用线程的机制。它是将多
  • 常用的队列主要以下两:(当然通过不同的实现方式,还可以延伸出很多不同类型的队列,DelayQueue就是其中的一) 先进先出(FIFO):先插入的队列的元素也最先出队列,类似于排队的功能。从某种程度上来说这种...
  • 文章目录创建线程池有哪几种方式? 创建线程池有哪几种方式?
  • 有些童鞋一直在使用线程池,但是,对于如何创建线程池仅仅停留在使用Executors工具类的方式,那么,创建线程池究竟存在哪几种方式呢?就让我们一起从创建线程池的源码来深入分析究竟哪些方式可以创建线程池。 ...
  • 有些童鞋一直在使用线程池,但是,对于如何创建线程池仅仅停留在使用Executors工具类的方式,那么,创建线程池究竟存在哪几种方式呢?就让我们一起从创建线程池的源码来深入分析究竟哪些方式可以创建线程池。使用...
  • 有些童鞋一直在使用线程池,但是,对于如何创建线程池仅仅停留在使用Executors工具类的方式,那么,创建线程池究竟存在哪几种方式呢?就让我们一起从创建线程池的源码来深入分析究竟哪些方式可以创建线程池。使用...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 204
精华内容 81
关键字:

创建线程池有哪几种