zoukankan      html  css  js  c++  java
  • Executors创建线程池有哪几种方式?

    Executors如何创建线程池?

    Executors 类是从 JDK 1.5 开始就新增的线程池创建的静态工厂类,它就是创建线程池的,但是很多的大厂已经不建议使用该类去创建线程池。原因在于,该类创建的很多线程池的内部使用了无界任务队列,在并发量很大的情况下会导致 JVM 抛出 OutOfMemoryError,直接让 JVM 崩溃,影响严重。

    但是 Executors 类究竟是如何使用的?

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

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试创建定长线程池
     * @author ConstXiong
     */
    public class TestNewFixedThreadPool {
    
    	public static void main(String[] args) {
    		//创建工作线程数为 3 的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
    		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    		//提交 6 个任务
    		for (int i = 0; i <6; i++) {
    			final int index = i;
    			fixedThreadPool.execute(() -> {
    				try {
    					//休眠 3 秒
    					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秒后...");
    		
    		//关闭线程池后,已提交的任务仍然会执行完
    		fixedThreadPool.shutdown();
    	}
    	
    }

    打印结果:

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

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

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试创建可缓存的线程池
     * @author ConstXiong
     */
    public class TestNewCachedThreadPool {
    	
    	public static void main(String[] args) {
    		//创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
    		ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    
    		for (int i = 0; i <6; i++) {
    			final int index = i;
    			cachedThreadPool.execute(() -> {
    				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秒后...");
    		
    		cachedThreadPool.shutdown();
    		
    	}
    	
    }
    

    打印结果可以看出,创建的线程数与任务数相等

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

    3. newScheduledThreadPool,创建定长线程池,可执行周期性的任务。

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 测试创建定长线程池,可执行周期性的任务
     * @author ConstXiong
     */
    public class TestNewScheduledThreadPool {
    
    	public static void main(String[] args) {
    		//创建定长线程池,可执行周期性的任务
    		ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
    		
    		for (int i = 0; i <3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			scheduledThreadPool.scheduleWithFixedDelay(() -> {
    					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秒后...");
    		
    		scheduledThreadPool.shutdown();
    
    	}
    }
    

    打印结果:

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

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

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试单线程的线程池
     * @author ConstXiong
     */
    public class TestNewSingleThreadExecutor {
    	
    	public static void main(String[] args) {
    		//单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
    		ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
    		
    		//提交 3 个任务
    		for (int i = 0; i <3; i++) {
    			final int index = i;
    			singleThreadPool.execute(() -> {
    				
    				//执行第二个任务时,报错,测试线程池会创建新的线程执行任务三
    				if (index == 1) {
    					throw new RuntimeException("线程执行出现异常");
    				}
    				
    				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秒后...");
    		
    		singleThreadPool.shutdown();
    	}
    
    }
    

    打印结果可以看出,即使任务出现了异常,线程池还是会自动补充一个线程继续执行下面的任务

    pool-1-thread-1 index:0
    Exception in thread "pool-1-thread-1" 
    java.lang.RuntimeException: 线程执行出现异常
    	at constxiong.concurrency.a011.TestNewSingleThreadExecutor.lambda$0(TestNewSingleThreadExecutor.java:21)
    	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    	at java.lang.Thread.run(Thread.java:748)
    4秒后...
    pool-1-thread-2 index:2
    

    5. newSingleThreadScheduledExecutor,创建单线程可执行周期性任务的线程池。

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 测试单线程可执行周期性任务的线程池
     * @author ConstXiong
     */
    public class TestNewSingleThreadScheduledExecutor {
    
    	public static void main(String[] args) {
    		//创建单线程可执行周期性任务的线程池
    		ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();
    		
    		//提交 3 个固定频率执行的任务
    		for (int i = 0; i <3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			singleScheduledThreadPool.scheduleAtFixedRate(() -> {
    				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秒后...");
    		
    		singleScheduledThreadPool.shutdown();
    	}
    	
    }
    

    打印机结果可以看出 0-2 任务都被执行了 2 个周期

    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秒后...

    6. newWorkStealingPool,创建任务可窃取线程池,空闲线程可以窃取其他任务队列的任务,不保证执行顺序,适合任务耗时差异较大。

    package constxiong.concurrency.a011;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 测试可任务窃取线程池
     * @author ConstXiong
     */
    public class TestNewWorkStealingPool {
    
    	public static void main(String[] args) {
    		//创建 4个工作线程的 任务可窃取线程池,如果不设置并行数,默认取 CPU 总核数
    		ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(4);
    		
    		for (int i = 0; i <10; i++) {
    			final int index = i;
    			workStealingThreadPool.execute(() -> {
    				try {
    					//模拟任务执行时间为 任务编号为0 1 2 的执行时间需要 3秒;其余任务200 毫秒,导致任务时间差异较大
    					if (index <= 2) {
    						Thread.sleep(3000);
    					} else {
    						Thread.sleep(200);
    					}
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}
    				System.out.println(Thread.currentThread().getName() + " index:" + index);
    			});
    		}
    		
    		try {
    			Thread.sleep(10000);//休眠 10 秒
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("10秒后...");
    	}
    	
    }
    

    打印结果可以看出,线程 ForkJoinPool-1-worker-0 把3-9的任务都执行完

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


     


     

    所有资源资源汇总于公众号



     

  • 相关阅读:
    Alpha 冲刺 (10/10)
    Alpha 冲刺 (9/10)
    Alpha 冲刺 (8/10)
    Alpha 冲刺 (7/10)
    Alpha 冲刺 (6/10)
    Alpha 冲刺 (5/10)
    18软工实践-团队现场编程实战(抽奖系统)
    Alpha 冲刺 (4/10)
    BETA(4)
    BETA(3)
  • 原文地址:https://www.cnblogs.com/ConstXiong/p/11955740.html
Copyright © 2011-2022 走看看