所有商用服务器都要用线程池
前言
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池可以对线程进行统一的分配、调优和监控,并有以下好处:1、降低资源消耗;2、提高响应速度;3、提高线程的可管理性。
Java1.5引入的Executor框架把任务的提交和执行进行解耦,只需要定义好任务,然后提交给线程池,而不用关心该任务是如何执行、被哪个线程执行,以及什么时候执行。
什么是线程池
首先创建一些线程,它们的集合称为线程池,当服务器接收到一个客户请求后,就从线程池中取出一个空的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。
在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程, 线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,如果没有空闲的,则需要等待其他线程运行完空出线程。
为什么要用线程池
在Java中,如果每当一个请求到达就创建一个新线程,开销是相当大的。在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源,甚至可能要比花在处理实际的用户请求的时间和资源要多得多。
除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。如果在一个JVM里创建太多的线程,可能会导致系统由于过度消耗内存或“切换过度”而导致系统资源不足。
为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务,这就是“池化资源”技术产生的原因。
使用线程池的好处
降低资源消耗;
提高响应速度;
提高线程的可管理性
什么时候使用线程池
1)单个任务处理的时间比较短
2)将需处理的任务的数量大
案例
/** * java1.5 提供的并发(concurrent)包 * java.util.concurrent.Executor是一个接口,表示线程池 * java.util.concurrent.Executors是工厂,包含工厂方用于创建Executor接口实例 */ public class ThreadPollDemo { public static void main(String[] args) { Executor threadPool = Executors.newFixedThreadPool(2); // 创建一个线程池,里面有创建好的2个线程,run方法空在那。 Process p1 = new Process(); Process p2 = new Process(); Process p3 = new Process(); threadPool.execute(p1);// 将p1提交到线程池执行,即执行其run方法 threadPool.execute(p2); threadPool.execute(p3); // 线程数只有两个,只有等p1和p2有一个执行完后,才能执行p3 } } class Process implements Runnable { static int index = 1; int id; public Process() { id = index++; } @Override public void run() { System.out.println(id + "开始....线程Id:" + Thread.currentThread().getId()); try{ Thread.sleep(2000); } catch(InterruptedException e){ e.printStackTrace(); } System.out.println(id + "结束...."); } }
CountDownLatch
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
public class ThreadPollDemo { public static void main(String[] args) { Integer threadNum = 5; CountDownLatch latch = new CountDownLatch(threadNum); ExecutorService executor = Executors.newFixedThreadPool(threadNum); for(int i = 0; i < threadNum; i++){ executor.execute(new TestThread(latch)); } try{ latch.await(); } catch(InterruptedException e){ Thread.currentThread().interrupt(); } System.out.println("所有线程执行结束..."); } } class TestThread implements Runnable { private CountDownLatch downLatch; public TestThread(CountDownLatch latch) { this.downLatch = latch; } @Override public void run() { try{ System.out.println("执行开始....线程Id:" + Thread.currentThread().getId()); Thread.sleep(2000); System.out.println("执行结束....线程Id:" + Thread.currentThread().getId()); } catch(Exception e){ } finally{ downLatch.countDown(); } } }
tomcat配置线程池问题
web server允许的最大线程连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。
tomcat安装目录下的conf目录下的server.xml文件中的<Connector />配置中
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="1000" minSpareThreads="50" maxIdleTime="600000"/>
配置完后 在Connector port=“8080”上加executor="tomcatThreadPool"
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />