关于线程池的笔记
对于并发,相信很多人生活中都有经历过。比如买火车票,它就是一个常见的并发案例,为了不让同时多个人买到同一个位置的这种情况的发生,就必须要让它有并发上的控制。
总结:
CPU与线程任务分别有:
单CPU单任务
单CPU多任务
多CPU多任务
多线程的优点:
资源利用率更好
程序设计有简单
程序响应更快
多线程的代价:
底层设计更复杂
上下文切换的开销:
上一个线程与下一个线程的切换,CPU处理时增加的开销
增加资源的消耗
采用线程池的优点:
重用存在的线程,减少对象的创建,消亡的开销。
性能佳可有效控制最大并发线程数,提高系统资源的使用率
同时避免过多资源竞争,避免堵塞,提供定时执行,定期执行,单线程,并发数控制等功能。
JAVA中怎么应用多线程?
一、继承Thread类
二、实现Runnable接口
注意:
虽然一个类可以同时继承类和实现接口,但是在多线程里Thread和Runnable是不可以糅合在一起用的。
why?
因为Thread是就绪状态,就绪状态是指已经生产好了,马上就可以用它,它有可运行状态和运行状态的变化。
而Runnable是可运行状态。它可以实现资源共享,资源保护。
顺便一提,serlvet中线程的不安全性,就是因为它用的是Thread。
线程池的出现
线程池不是一种设计模式,是一种使用模式,使用方式。
它的出现是由于线程的生命周期自身引起的问题,创建线程和销毁线程给CPU带来了很大的开销。
而且线程的生命周期和数量都是可控的。
最后为了应付这种浪费情况,线程池这种技术就诞生了。
由线程池以最小线程数创建线程分配给使用者,当线程不够用的时候,线程池会维护和新增线程,直到最大数量为止。
通过线程池,简化了代码,提高开发效率,节约维护成本。
并发框架
来自java.util.concurrent类
一、Future
1.get() :表示异步计算的结果,利用get获取计算成果
2.cancel() :可取消性,在运行的过程中可以取消它,但是运行结束后却不能取消
3.isCancelled :查看任务是否取消了
4.isDone() :查看任务是否完成了
二、Executor
1.灵活且强大的异步执行框架
2.支持多种不同类型的任务执行策略
3.提供了一种标准的方法将任务的提交过程和执行过程解耦开发
4.基于生产者-消费者模式
提交任务的线程为生产者,执行任务的线程为消费者
用Runnable表示任务
5.Executor的实现还提供了对生命周期的支持,以及统计信息的收集,应用程序管理机制和性能监视等机制。
6.Executor框架包含:
线程池,Executor,Executors,ExecutorService,
CompletionService,Future,Callable等
其中最为基本的方法
execute()方法:用于接收用户提交任务
Submit()方法:执行任务并返回结果
execute(Runnable command):未来某个时间执行给定的命令
创建方式:
//创建一个固定大小为5的线程池,即5个线程
ExecutorService es = Executors.newFixedThreadPool(5);
//提供10个任务
for(int i=0;i<10;i++){
//WorkerThreadDemo为一个简单线程执行demo
//里面有一句简单打印
//System.out.println(Thread.currentThread().getName()+"is"+this.i);
WorkerThreadDemo worker = new WorkerThreadDemo("Thread"+i);
//线程池接收任务
es.execute(worker);
}
//会顺序关闭任务,谁先完成先关闭谁
es.shutdown();
while(! es.isTerminated()){
//isTerminated()判断任务是否全部完成
//全部完成后才能执行最后一步的输出
}
System.out.println("所有任务完成!");
/**
*创建了10个任务,线程池中却只有5个线程可用,但是消费者-生产者模式中,消费者是任务队列的结构,
*所以剩下5个会等待线程结束后才开始
***/