熟悉java多线程的 朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor。大家可能 了解到它的原理,甚至看过它的源码;但是就像我一样,大家可能对它的作用存在误解。现在问题来了,jdk为什么要提供java线程池?使用java线程池 对于每次都创建一个新Thread有什么优势?
创新互联建站是一家集网站建设,临川企业网站建设,临川品牌网站建设,网站定制,临川网站建设报价,网络营销,网络优化,临川网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。
十年的长安网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。成都营销网站建设的优势是能够根据用户设备显示端的尺寸不同,自动调整长安建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联建站从事“长安网站设计”,“长安网站推广”以来,每个客户项目都认真落实执行。
对线程池的误解
很长一段时间里我一直以为java线程池是为了提高多线程下创建线程的效率。创建好一些线程并缓存在线程池里,后面来了请求(Runnable)就 从连接池中取出一个线程处理请求;这样就避免了每次创建一个新Thread对象。直到前段时间我看到一篇Neal Gafter(和Joshua Bloch合著了《Java Puzzlers》,现任职于微软,主要从事.NET语言方面的工作)的访谈,里面有这么一段谈话(http://www.infoq.com/cn/articles/neal-gafter-on-java):
乍一看,大神的思路就是不一样:java线程池是为了防止java线程占用太多资源?
虽然是java大神的访谈,但是也不能什么都信,你说占资源就占资源?还是得写测试用例测一下。
首先验证下我的理解:
java线程池和创建java线程哪个效率高?
直接上测试用例:
- public class ThreadPoolTest extends TestCase {
- private static final int COUNT = 10000;
- public void testThreadPool() throws InterruptedException {
- CountDownLatch countDownLatch = new CountDownLatch(COUNT);
- ExecutorService executorService = Executors.newFixedThreadPool(100);
- long bg = System.currentTimeMillis();
- for (int i = 0; i < COUNT; i++) {
- Runnable command = new TestRunnable(countDownLatch);
- executorService.execute(command);
- }
- countDownLatch.await();
- System.out.println("testThreadPool:" + (System.currentTimeMillis() - bg));
- }
- public void testNewThread() throws InterruptedException {
- CountDownLatch countDownLatch = new CountDownLatch(COUNT);
- long bg = System.currentTimeMillis();
- for (int i = 0; i < COUNT; i++) {
- Runnable command = new TestRunnable(countDownLatch);
- Thread thread = new Thread(command);
- thread.start();
- }
- countDownLatch.await();
- System.out.println("testNewThread:" + (System.currentTimeMillis() - bg));
- }
- private static class TestRunnable implements Runnable {
- private final CountDownLatch countDownLatch;
- TestRunnable(CountDownLatch countDownLatch) {
- this.countDownLatch = countDownLatch;
- }
- @Override
- public void run() {
- countDownLatch.countDown();
- }
- }
- }
这里使用Executors.newFixedThreadPool(100)是为了控制线程池的核心连接数和***连接数一样大,都为100。
我的机子上的测试结果:
testThreadPool:31
testNewThread:624
可以看到,使用线程池处理10000个请求的处理时间为31ms,而每次启用新线程的处理时间为624ms。
好了,使用线程池确实要比每次都创建新线程要快一些;但是testNewThread一共耗时624ms,算下平均每次请求的耗时为:
624ms/10000=62.4us
每次创建并启动线程的时间为62.4微秒。根据80/20原理,这点儿时间根本可以忽略不计。所以线程池并不是为了效率设计的。
java线程池是为了节约资源?
再上测试用例:
- public class ThreadPoolTest extends TestCase {
- public void testThread() throws InterruptedException {
- int i = 1;
- while (true) {
- Runnable command = new TestRunnable();
- Thread thread = new Thread(command);
- thread.start();
- System.out.println(i++);
- }
- }
- private static class TestRunnable implements Runnable {
- @Override
- public void run() {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
以上用例模拟每次请求都创建一个新线程处理请求,然后默认每个请求的处理时间为1000ms。而在我的机子上当请求数达到1096时会内存溢出:
java.lang.OutOfMemoryError: unable to create new native thread
为什么会抛OOM Error呢?因为jvm会为每个线程分配一定内存(JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K,也可以通过jvm参数-Xss来设置),所以当线程数达到一定数量时就报了该error。
设想如果不使用java线程池,而为每个请求都创建一个新线程来处理该请求,当请求量达到一定数量时一定会内存溢出的;而我们使用java线程池的话,线程数量一定会<=maximumPoolSize(线程池的***线程数),所以设置合理的话就不会造成内存溢出。
现在问题明朗了:java线程池是为了防止内存溢出,而不是为了加快效率。
浅谈java线程池
上文介绍了java线程池启动太多会造成OOM,使用java线程池也应该设置合理的线程数数量;否则应用可能十分不稳定。然而该如何设置这个数量呢?我们可以通过这个公式来计算:
(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Max number of threads
MaxProcessMemory 进程***的内存
JVMMemory JVM内存
ReservedOsMemory JVM的本地内存
ThreadStackSize 线程栈的大小
MaxProcessMemory
MaxProcessMemory:进程***的寻址空间,当然也不能超过虚拟内存和物理内存的总和。关于不同系统的进程可寻址的***空间,可参考下面表格:
Maximum Address Space Per Process | |
Operating System | Maximum Address Space Per Process |
Redhat Linux 32 bit | 2 GB |
Redhat Linux 64 bit | 3 GB |
Windows 98/2000/NT/Me/XP | 2 GB |
Solaris x86 (32 bit) | 4 GB |
Solaris 32 bit | 4 GB |
Solaris 64 bit | Terabytes |
JVMMemory
JVMMemory: Heap + PermGen,即堆内存和***代内存和(注意,不包括本地内存)。
ReservedOsMemory
ReservedOSMemory:Native heap,即JNI调用方法所占用的内存。
ThreadStackSize
ThreadStackSize:线程栈的大小,JDK5.0以后每个线程堆栈大小默认为1M,以前每个线程堆栈大小为256K;可以通过jvm参数-Xss来设置;注意-Xss是jvm的非标准参数,不强制所有平台的jvm都支持。
如何调大线程数?
如果程序需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:
MaxProcessMemory 使用64位操作系统
JVMMemory 减少JVMMemory的分配
ThreadStackSize 减小单个线程的栈大小
本文名称:Java线程池的那些事
当前链接:http://www.shufengxianlan.com/qtweb/news24/494524.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联