A:什么是线程池
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目
B:为什么要使用线程池?
如果程序中有大量短时间任务的线程任务,由于创建和销毁线程需要和底层 *** 作系统交互,大量时间都耗费在创建和销毁线程上,因而比较浪费时间,系统效率很低
而线程池里的每一个线程任务结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用,因而借助线程池可以提高程序的执行效率
这个是比较官方的解释,为了好理解,提出一个有背景的问题。有100个小人需要从车站到目的地,方式是乘坐出租车,直接叫100个出租车,会占用大量的交通资源。比较好的方法是,安排一定数目的出租车(核心线程数)然后循环接送,被分配到车的小人,进行运行行为(执行任务)。剩下的小人则处于等待状态,等待有出租车(线程)完成任务后唤醒。也减少每一次出来一个小人就要重新叫车,出租车使用一次就损毁的时间问题。
所以综合一下
1.线程池是一种用于提高效率和服务器性能的技术。
2.主要优点两个:(1)减少了线程的创建和损毁(2)控制线程的数量,减少系统资源的占用,就如同车站不可能有100个出租车泊位一样,系统也无法处理天量的线程生成
2.如何使用线程池?示例代码这一部分其实我本身并不是很理解,希望通过写教程的方式复习,并且找到自己所并不会的部分。(费曼学习法)
import java.util.ArrayList;
import java.util.List;
/*梳理一下思路
1.为什么要使用线程池:
2.如何使用
首先需要一个线程池队列
包括一个列表和他的长度——即核心线程数量
理解起来就是可以同时运行的线程数量
*
*/
public class ThreadPool {
// 任务队列
private List listRunnable = new ArrayList<>();
// 线程池维护的核心县城
private List listWork = new ArrayList<>();
//初始化核心线程
// 根据CORE创建核心线程
public ThreadPool(int core){
for (int i = 0; i
import java.util.List;
//线程池中处理提交任务的线程
//从任务队列中取出提交待处理的任务
public class WorkThread implements Runnable{
private List listRunnable;
public WorkThread(List listRunnable) {
this.listRunnable = listRunnable;
}
@Override
public void run() {
Runnable runnable =null;
while(true) {
// 判断任务队列是否有待处理
synchronized (listRunnable) {
while (listRunnable.isEmpty()) {
try {
System.out.println(Thread.currentThread().getName()+"进入等待状态");
listRunnable.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 取出任务执行
runnable=listRunnable.remove(0);
}
runnable.run();
}
}
}
public class Test {
public static void main(String[] args) {
ThreadPool tp = new ThreadPool(3);
for (int i = 0; i <20 ; i++) {
tp.addWork(new TestRun(i));
}
}
static class TestRun implements Runnable{
int i;
public TestRun(int i) {
this.i = i;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}System.out.println(Thread.currentThread().getName()+":处理任务 "+i);
}
}
}
这个是照着老师的代码写的,自己还要在写一个用lock锁方法的实现。之后补上
3.注意事项线程池大小问题
如果我们设置的线程池数量太小的话,如果同一时间有大量任务/请求需要处理,可能会导致大量的请求/任务在任务队列中排队等待执行,甚至会出现任务队列满了之后任务/请求无法处理的情况,或者大量任务堆积在任务队列导致OOM。这样很明显是有问题的! CPU 根本没有得到充分利用。
但是,如果我们设置线程数量太大,大量线程可能会同时在争取 CPU 资源,这样会导致大量的上下文切换,从而增加线程的执行时间,影响了整体执行效率。
具体线程池大小的设计应当取决于任务队列的类型
CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
I/O 密集型任务(2N): 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。
如何判断是 CPU 密集任务还是 IO 密集任务?
CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。单凡涉及到网络读取,文件读取这类都是 IO 密集型,
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)