线程池的使用

概念:解决了频繁的创建和销毁线程,在线程池中总有几个活跃的线程, 当我们需要使用时,拿走池子里的空闲线程即可, 用完后还给池子!

线程池工厂类:Excutors

我们可以根据工厂类得到不同工作特性的线程池

1. newFixedThreadPool(): 该方法可以得到固定线程数据的线程池

2. newSingleThreadPool(): 该方法返回只有一个线程的线程池

3. newCachedThreadPool(): 该方法返回一个根据实际情况调成线程数量的线程池

4. newSingleThreadScheduleExcutor(): 该方法返回一个ScheduleExcutorService对象。线程数量为1, 其在接口ExecutorService接口上扩展了任务调度

5. newScheduleThreadPool(): 该方法返回一个ScheduleExcutorService对象, 可以指定线程数量

计划任务: ScheduleExcutorService

核心API:

A. schedule(Runnable r, long delay, TimeUnit time) 会在给定时间执行一次任务调度

B. scheduleAtFixedRate(Runnable r, long inititalDelay , long period, TimeUnit time): 周期性调度==> inititalDelay + n*period    比如说任务执行时间1秒钟, 周期时间2秒钟, 那么这个任务会每隔俩秒执行一次。 但是执行任务大于了周期时间,比如5秒,那么将会每隔5秒立马调度一次。inititalDelay只会执行一次延迟

public static void main(String[] args) {
	
	ScheduledExecutorService pool = Executors.newScheduledThreadPool(1) ;
	pool.scheduleAtFixedRate(new Runnable() {
		
		@Override
		public void run() {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			Date date = new Date() ;
			System.out.println(date.getSeconds());
		
		}
	}, 0, 2, TimeUnit.SECONDS) ;
	
}

B. scheduleWithFixedRate(Runnable r, long inititalDelay , long period, TimeUnit time): 周期性调度==> n*inititalDelay + n*period   每次周期调度时间都是延迟加周期。 

刨根究底:核心线程池内部实现 ThreadPoolExcetor

我们上述讲的工厂类产生的几种线程池都是通过ThreadPoolExcetor包装得到的!首先看一下它的内部构造:

public static void main(String[] args) {
		ThreadPoolExecutor executor = new ThreadPoolExecutor(
				nThreads,   // 核心线程数
				maxSize,   // 最大线程数量
				keepAliveTime,  // 超过核心线程数的最大存活时间
				TimeUnit.MILLISECONDS,  // 时间单位
				new LinkedBlockingQueue<Runnable>(),  // 任务队列,存储尚未执行的任务
				Executors.defaultThreadFactory(),  // 线程工厂, 创建线程的, 默认即可
				// 拒绝策略
				new AbortPolicy()  
				);
	}

任务队列:BlockingQueue 用于存储Runnable对象

1. 直接提交的队列: SysnchronousQueue===>newCachedThreadPool使用的这个队列, 核心线程数为0, maxSize无穷大, 每次使用空闲线程执行任务, 如果没有加入队列, 队列则直接提交,会迫使线程池增加新的线程。

2. 有界任务队列: ArrayBlockingQueue. 如果当前任务执行, 实际线程数小于核心线程数,则创建新线程, 一旦超过了核心线程即加入等待队列,这时任务队列满了,核心线程中还没有空闲线程, 即在不大于MaxSize线程总数的情况下, 开辟新线程。 换言之, 除非系统非常繁忙, 否则确保线程数维持在核心线程数量上。

3. 无界任务队列: 通过LinkedBlockingQueue实现, 与有界相比, 除非系统资源耗尽, 否则不会出现任务入队失败的情况。 线程在达到核心线程数时, 不在增加。

4. 优先级队列: PriorityBlockingQueue,   带有优先级的无界任务队列

使用自定义线程池, 根据应用情况, 选择合适的缓冲并发队列。

拒绝策略:

AbortPolicy策略: 直接抛出异常, 阻止系统正常运行

CallerRunsPolicy: 只有线程池未关闭, 即使用调用者线程,执行该任务

DisCardOlderstPolicy:  丢弃最老的请求

DiscardPolicy: 默默丢弃无法处理的请求

我们也可以通过RejectedExcetionHandler实现自定义策略

 在线程池使用中, 很多时候可能出现一些异常, 但是我们看不见完整的异常信息,1.  这时候我们只需要把submit() 改为 execute()

2. 

public class MyEexcutors extends ThreadPoolExecutor {
	
	public static void main(String[] args) {
		ThreadPoolExecutor eexcutors = 
				new MyEexcutors(0, Integer.MAX_VALUE, 0L, TimeUnit.SECONDS, new SynchronousQueue<>()) ;
		for(int i=0; i<5; i++) {
			eexcutors.execute(new DivTask(100, i));
		}
	}

	public MyEexcutors(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
		
	}	
	
	@Override
	public void execute(Runnable task) {
		super.execute(wrap(task, clientTrace(), Thread.currentThread().getName()));
	}

	private Runnable wrap(Runnable task, final Exception clientTrace, String name) {
		
		return new Runnable() {
			
			@Override
			public void run() {
				try {
					task.run();
				}catch (Exception e) {
					clientTrace.printStackTrace();
					throw e ;
				}
				
			}
		};
	}
	
	private Exception clientTrace() {
		
		return new Exception("Client stack trace");
	}
}
public class DivTask implements Runnable {
	
	int a ;
	int b ;
	public DivTask(int a, int b) {
		this.a = a ;
		this.b = b ;
	}
	@Override
	public void run() {
		double re = a/b ;
		System.out.println(re);		
	}
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值