利用线程池来创建和管理线程

        传统的创建线程的方式有两种:继承Thread类和实现Runnable接口,Java SE5的java.util.concurrent包中放入执行器(Executor)将为你管理Thread对象,先来回顾以传统方法创建线程的方式:

public class CreateThreadByImplRunnable implements Runnable{
	protected int countDown = 10;
	private static int taskCount = 0;
	private int id = taskCount++;
	
	public CreateThreadByImplRunnable(int countDown){
		this.countDown = countDown;
	}
	
	public String statues(){
		return "#" + id + "(" + 
				(countDown > 0 ? (countDown + "),"): "Liftoff!)");
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(countDown-- > 0){
			System.out.print(statues());
			Thread.yield();   //告知线程调度器此时是切换到其他线程的最佳时机
		}
		System.out.println();
	}
	
	public static void main(String[] args) throws InterruptedException {
		Thread thread = new Thread(new CreateThreadByImplRunnable(10));
		System.out.println("单个任务:");
		thread.start();
		/**重复调用start方法运行时报错*/
		//thread.start();
		thread.join();
		System.out.println();
		System.out.println("多个任务:");
		for(int i = 0;i < 10;i++){
			new Thread(new CreateThreadByImplRunnable(10)).start();
		}
	}
}

将上述代码改成以线程池创建线程(利用CachedThreadPool类)

public class CreateThreadByExecutor {
	
	//用CachedThreadPool来执行任务,CachedThreadPool会为每个任务创建一个线程
	@Test
	public void test1(){
		ExecutorService exec = Executors.newCachedThreadPool();
		for(int i = 0;i < 100;i++){
			exec.execute(new CreateThreadByImplRunnable(10)); //从结果来看,与自己手动创建线程没什么区别
		}
		exec.shutdown(); 
	}
}

值得注意的是shutdown方法,该方法可以防止新任务被提交给这个Executor,下面介绍一下newCachedThreadPool方法:

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

该方法是Executors类的静态方法,返回一个Executor,类似于工厂模式,再来看下ThreadPoolExecutor类:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

5个参数,意义分别如下:

corePoolSize为0,maximumPoolSize为Integer.MAX_VALUE,意味着线程数量可以为任意整数

keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;

采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,没什么实际作用

那么使用CachedThreadPool有什么好处呢?最明显的是可以复用线程,传统分方式每一个任务都会创建一个线程,而使用CachedThreadPool首先会检查线程池里有没有空闲线程,如果有直接拿来用,没有的话再创建。

除了CachedThreadPool类以外,concurrent还提供了另外3种线程池FixedThreadPool、SingleThreadExecutor、ScheduiedThreadPool,分别作介绍

(1)FixedThreadPool

    使用有线的线程集来执行任务:

public class FIxedThreadPoolTest {
	public static void main(String[] args) {
		Executor exec = Executors.newFixedThreadPool(5);
		for(int i = 0;i < 10;i++){
			exec.execute(new RunClass());
		}
	}
	
	public static class RunClass implements Runnable{
		private static int count = 0;
		protected int threadNo = ++count;

		@Override
		public void run() {
			// TODO Auto-generated method stub
			System.out.println("Thread"	+ threadNo);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}

输出结果(不固定):

Thread4
Thread5
Thread1
Thread2
Thread3
Thread6
Thread7
Thread10
Thread9
Thread8

在上述代码中,创建FixedThreadPool时我给它大小设定为5,然后让它去执行10个任务,为了体现FixedThreadPool与CachedThreadPool的不同之处让每个任务至少持续1秒,这样做有什么效果呢?从结果输出来看有两个效果:

1、结果看起来无序,实际前5个任务必然比后5个任务先执行

2、后5个任务大约等待1秒后才开始执行

其实这个不难理解,ThreadPool里维护着一个workQueue,当ThreadPool里的处于Running状态的线程数饱和时,新的任务就会放到WorkQueue里,WorkQueue是用LinkedBlockingQueue实现,关于LinkedBlockingQueue,它最大的特点就是阻塞,这里不做深究

(2)SingleThreadExecutor

    SingleThreadExecutor就像是数量为1的FixedThreadPool。如果向SingleThreadExecutor提交多个任务它会按照提交顺序      一个一个执行

(3)ScheduledThreadPool

    主要适用那些需要定时或周期性执行的任务,示例代码如下:

public class ScheduledThreadPoolTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ScheduledExecutorService secs = Executors.newScheduledThreadPool(5);
		secs.schedule(new RunTask(), 3, TimeUnit.SECONDS);    //延迟3秒执行
		secs.scheduleAtFixedRate(new RunTask(), 1, 3, TimeUnit.SECONDS);  //1秒后每3秒执行一次
	}
	
	public static class RunTask implements Runnable{

		@Override
		public void run() {
			// TODO Auto-generated method stub
			System.out.println("ScheduledThreadPool Test");
		}
		
	}
}

总结:

    为了更好的维护线程的使用及提高性能,Java SE5推出了线程池的概念,提供4种线程池的实现方式,分别为:CachedThreadPool、FixedThreadPool、SingleThreadExecutor以及ScheduledThreadExecutor,在日常开发中应当根据业务场景合理使用线程池技术,本人并不反对滥用线程池技术,对个人学习来说,滥用好过不用,但是一定要在前期的滥用中吸取经验,最后方能精用

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值