深入浅出Java线程池

使用线程池的好处:1、线程可以复用,减少创建、销毁线程的资源开销;2、避免创建线程,提高效率;3、便于对线程统一管理、监控等。大神Doug Lea为我们提供了多种构建线程池的方法:

1、直接构造ThreadPoolExecutor对象

源码分析:

    //构造方法1:使用默认的线程工厂,默认的拒绝策略(中止策略,直接抛RejectedExecutionException)
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }


    //构造方法2:可以自定义线程工厂
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }


    //构造方法3:可以自定义拒绝策略
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }


    //构造方法4:可以自定义线程工厂和拒绝策略
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

使用示例:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 直接构造线程池,new ThreadPoolExecutor
 * 使用灵活,方便扩展
 */
public class ThreadPoolExecutorTest {
	
	private static final int CORE_POOL_SIZE=10;
	private static final int MAXIMUM_POOL_SIZE=15;
	private static final int KEEP_ALIVE_TIME=0;
	
	//使用有界队列(Integer.MAX_VALUE)和Executors.newFixedThreadPool类似
	private ExecutorService threadPoolExecutor=new ThreadPoolExecutor(
			CORE_POOL_SIZE, //核心工作线程数
			MAXIMUM_POOL_SIZE, //线程池最大线程数
			KEEP_ALIVE_TIME, //空闲线程等待任务的时间
			TimeUnit.MILLISECONDS, 
			new LinkedBlockingQueue<Runnable>()//有界队列(Integer.MAX_VALUE),可以改为必须指定长度的有界队列ArrayBlockingQueue
			//ThreadFactory 可以指定线程构造工厂
			//RejectedExecutionHandler 可以指定队列满后的拒绝策略,理论来说如果队列太长,则此策略不易被触发
			);
	
	//指定队列长度,要注意拒绝策略
	private ExecutorService threadPoolExecutor2=new ThreadPoolExecutor(
			CORE_POOL_SIZE, //核心工作线程数
			MAXIMUM_POOL_SIZE, //线程池最大线程数
			KEEP_ALIVE_TIME, //空闲线程等待任务的时间
			TimeUnit.MILLISECONDS, 
			new ArrayBlockingQueue<Runnable>(5),//10个工作,5个扩展,5个排队,理论上最多并发15个,排队5个,超过数量会触发拒绝策略
			//ThreadFactory 可以指定线程构造工厂
			
			new ThreadPoolExecutor.AbortPolicy() //中止执行策略,抛异常
			//其他几种拒绝策略是:
			//ThreadPoolExecutor.CallerRunsPolicy//立即执行
			//ThreadPoolExecutor.DiscardPolicy//丢弃当前,不做处理
			//ThreadPoolExecutor.DiscardOldestPolicy//丢弃最早的,立即执行当前线程
			//可见几种策略都不太好用
			);
	
	public ThreadPoolExecutorTest() {
	}
	
	private void test() {
		for(int i=0;i<100;i++) {
			final int num=i;
			threadPoolExecutor.submit(new Runnable() {
				public void run() {
					System.out.println("num:"+num);
					try {
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		threadPoolExecutor.shutdown();
	}
	
	private void test2() {
		for(int i=0;i<100;i++) {
			final int num=i;
			threadPoolExecutor2.submit(new Runnable() {
				public void run() {
					System.out.println("num:"+num);
					try {
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		threadPoolExecutor2.shutdown();
	}

	public static void main(String[] args) {
		ThreadPoolExecutorTest threadPoolExecutorTest=new ThreadPoolExecutorTest();
		//threadPoolExecutorTest.test();
		threadPoolExecutorTest.test2();
	}
}

2、通过Executors工具类创建

2.1、Executors.newFixedThreadPool构造一个固定工作线程数量,有个有界队列(Integer.MAX_VALUE)可以支持排队的线程池

源码分析:

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

可见,最终构造的还是ThreadPoolExecutor对象,其中corePoolSize=maximumPoolSize,空闲线程不会等待,有个有界队列(Integer.MAX_VALUE)负责缓存排队(注意没有指定长度)

使用示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 固定数量的工作线程,有有界队列(Integer.MAX_VALUE)支持排队进入
 */
public class FixedThreadPoolTest {

	private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);//固定线程池数量

	/**
	 * 
	 */
	public FixedThreadPoolTest() {
	}

	private void test() {
		for (int i = 0; i < 100; i++) {
			final int num = i;
			fixedThreadPool.submit(new Runnable() {
				public void run() {
					System.out.println("NO:" + num + ",Name:" + Thread.currentThread().getName());
					try {
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}

		fixedThreadPool.shutdown();
	}

	public static void main(String[] args) {
		FixedThreadPoolTest fixedThreadPoolTest = new FixedThreadPoolTest();
		fixedThreadPoolTest.test();
	}
}

2.2、Executors.newSingleThreadExecutor构造一个只有一个工作线程的线程池,其和newFixedThreadPool一样,也有个有界队列(Integer.MAX_VALUE)支持任务排队

源码分析:

    //corePoolSize=maximumPoolSize=1,外加一个有界队列(Integer.MAX_VALUE)支持排队
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

使用示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 固定线程大小为1,有个有界队列(Integer.MAX_VALUE)可以方便排队
 */
public class SingleThreadExecutorTest {

	private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

	public SingleThreadExecutorTest() {
	}

	private void test() {
		for (int i = 0; i < 100; i++) {
			final int num = i;
			singleThreadExecutor.submit(new Runnable() {
				public void run() {
					System.out.println("num:" + num);
				}
			});
		}
		singleThreadExecutor.shutdown();
	}

	public static void main(String[] args) {
		SingleThreadExecutorTest singleThreadExecutorTest = new SingleThreadExecutorTest();
		singleThreadExecutorTest.test();
	}

}

2.3、Executors.newCachedThreadPool创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源。

源码分析:

    //注意:其和newFixedThreadPool/newSingleThreadExecutor是不一样的,
    //其空闲线程的超时时间是60秒,且使用了SynchronousQueue一个不存储元素的阻塞队列,
    //每一个put操作必须等待一个take操作,否则不能继续添加元素
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

使用示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。
 * 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。
 * 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源。
 */
public class CachedThreadPoolTest {

	private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//可以看做是没有排队队列,有线程就执行了
	
	//自定义,看是否会阻塞
	private ExecutorService cachedThreadPool2= new ThreadPoolExecutor(
			5, 
			10,
            60L, 
            TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());//本构造限定了大小,而这里又类似没有队列,会导致线程池满后抛异常

	public CachedThreadPoolTest() {
	}
	
	private void test() {
		for (int i = 0; i < 100; i++) {
			final int num = i;
			cachedThreadPool.submit(new Runnable() {
				public void run() {
					System.out.println("num:" + num);
				}
			});
		}
		cachedThreadPool.shutdown();
	}
	
	private void test2() {
		for (int i = 0; i < 100; i++) {
			final int num = i;
			cachedThreadPool2.submit(new Runnable() {
				public void run() {
					System.out.println("num:" + num);
					try {
						TimeUnit.SECONDS.sleep(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			});
		}
		System.out.println("循环完了");
		cachedThreadPool2.shutdown();
	}

	public static void main(String[] args) {
		CachedThreadPoolTest cachedThreadPoolTest=new CachedThreadPoolTest();
		//cachedThreadPoolTest.test();
		cachedThreadPoolTest.test2();
	}
}

2.4、Executors.newScheduledThreadPool创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。

源码分析:

    //注意这里构造的是:ScheduledThreadPoolExecutor
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

使用示例:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 可以延时执行,或定时执行,用到了:DelayedWorkQueue
 */
public class ScheduledThreadPoolTest {

	private ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
	private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	public ScheduledThreadPoolTest() {
	}
	
	private String getCurrentTime() {
		return simpleDateFormat.format(Calendar.getInstance().getTime());
	}

	private void test() {
		// 就像其他线程池一样直接执行任务
		/*
		scheduledThreadPool.submit(new Runnable() {
			public void run() {
				System.out.println("直接执行");
			}
		});
		*/
		
		// 延时执行后,再按固定间隔执行
		/*
		scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
			public void run() {
				System.out.println(getCurrentTime()+" scheduleWithFixedDelay");
			}
		}, 1, 2, TimeUnit.SECONDS);
		*/

		// 延时执行后,再定时执行
		scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
			public void run() {
				System.out.println(getCurrentTime()+" scheduleWithFixedDelay");
			}
		}, 1, 2, TimeUnit.SECONDS);
	}

	public static void main(String[] args) {
		ScheduledThreadPoolTest scheduledThreadPoolTest=new ScheduledThreadPoolTest();
		scheduledThreadPoolTest.test();
	}
}

猜你喜欢

转载自blog.csdn.net/tobearc/article/details/87456274