JUC:ExecutorService使用

new Thread的弊端:

new Thread(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
    }
}).start();

1.线程的创建和释放,需要占用不小的内存和资源,每次new Thread新建对象性能差。

2.线程缺乏统一管理,相互之间存在资源竞争,可能会占用过多资源而导致死机或者OOM

3.功能单一,缺乏定时执行,定期执行,线程中断等。

ExecutorService的优点:

1,重用存在的线程,减少对象创建、消亡的开销,性能较好。

2.可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

3.提供定时执行,定期执行,单线程,并发数控制等功能。

Java线程池

ExecutorService是Java提供的线程池,也就是,每次需要使用线程时,可以通过Executor获取线程。它可以有效控制最大并发线程数,提高系统资源使用率,同时避免过多资源竞争阻塞,同时提供定时执行、定期执行、单线程、并发数控制等功能,也不用使用TimeTask了。

Java通过Executors提供四种线程池:

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor创建一个单线程化线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。

ExectorService的创建方式

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

通过看源码得出:所有的线程池都是通过上面这个方法来创建的。

corePoolSize:核心线程数,一旦创建将不再释放。如果创建的线程数还没有达到指定的核心线程数,将会继续创建新的核心线程,直到达到最大核心线程数后,核心线程将不再增加;如果没有空闲的核心线程,同时又未达到最大线程数,则将继续创建非核心线程;如果核心线程数等于最大线程数,则当核心线程都处于激活状态时,任务将被挂起,等待空闲核心线程来执行。

maximumPoolSize:最大线程数,允许创建的最大线程数量。如果最大线程数量等于核心线程数,则无法创建非核心线程;如果非核心线程处于空闲时,超过设置的空闲时间,则将被回收,释放占用的资源。

keepAliveTime:当线程空闲时,所允许保存的最大时间,超过这个时间,线程将被释放销毁,只针对非核心线程。

util:时间单位,TimeUnit.SECONDS等

workQueue:任务队列,存储暂时无法执行的任务,等待空闲线程来执行任务。

threadFactory:线程工程,用于创建线程

handler:当线程边界和队列容量已经达到最大时,用于处理阻塞时的程序。

下面分别说下各个线程池:

1.newCacheThreadPool 可缓存线程池

ExecutorService cachePool = Executors.newCachedThreadPool();

具体创建源码:

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

可以看到,创建的都是非核心线程,而且最大线程数为Integer的最大值,空闲线程的存活时间是1分钟,如果有大量耗时任务,则不适合该创建方式,它只适用于生命周期短的任务。

测试代码:

public class ExectorServiceTest {
public static void main(String[] args) {
	ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
	for (int i = 0; i < 10; i++) {
	     int index = i;
	    try {
	        Thread.sleep(index * 1000);
	    } catch (InterruptedException e) {
	        e.printStackTrace();
	    }

	    cachedThreadPool.execute(new Runnable() {
	        @Override
	        public void run() {
	            System.out.println(Thread.currentThread().getName()+"  "+index);
	        }
	    });
	}
    cachedThreadPool .shutdown();
}
}

运行结果:  执行第二个任务时第一个任务已经完成,会复用第一个任务的线程,而不是每次新建线程

2.newFixedThreadPool 固定线程数线程池

Executors.newFixedThreadPool(3);

具体源码:

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

也就是创建固定数量的可复用线程数(核心线程不会被释放所以是可复用的),来执行任务。当线程数达到最大核心线程数,则加入队列等待有空闲线程是再执行。

public class ExectorServiceTest {
public static void main(String[] args) {
	ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
	for (int i = 0; i < 6; i++) {
		final Integer index = i;
	    fixedThreadPool.execute(new Runnable() {
	        @Override
	        public void run() {
	            try {
	                System.out.println(index+"->"+index.hashCode());
	                Thread.sleep(2000);
	            } catch (InterruptedException e) {
	                // TODO Auto-generated catch block
	                e.printStackTrace();
	            }
	        }
	    });
	}
	fixedThreadPool.shutdown();
}
}

线程池大小为3,每个任务输出index后sleep1秒,所以每隔一秒打印3个数字,打印截图:

3.newScheduledThreadPool 定长线程池 支持定时和周期性任务

ExecutorService scheduledPool = Executors.newScheduledThreadPool(5);

具体源码:

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

可用于替代handler.postDelay和Timer定时器等延时和周期性任务。

public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                     long initialDelay,
                                                     long delay,
                                                     TimeUnit unit);

schedule方法:在dalay unit(即几秒后或者几分钟等)后执行

scheduleAtFixedRate方法:initialDelay + x * period 首先暂停initialDelay然后每次间隔period

sheduleWithFixedDelay方法:(initialDelay +  period)*n每次都间隔(initialDelay +  period)

public class ExectorServiceTest {
public static void main(String[] args) {
	ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
	scheduledThreadPool.schedule(new Runnable() {
	    public void run() {
	        System.out.println("delay 3 seconds");
	    }
	},3, TimeUnit.SECONDS);
	scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
		 @Override
			public void run() {
				System.out.println("delay 1 seconds, and excute every 3 seconds");
			}
		}, 1, 3, TimeUnit.SECONDS);
}
}

打印结果:

4.newSingleThreadExecutor 单线程池

ExecutorService singlePool = Executors.newSingleThreadExecutor();

具体源码:

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

顾名思义就是创建一个核心线程,保证任务按FIFO顺序(先进先出)一个个执行。

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {

        @Override
        public void run() {
            try {
                System.out.println(index);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    });
}

现在大多数GUI程序都是单线程。适用于批量删除,批量安装等不适合并发但是可能IO阻塞的操作。    

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值