关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java线程池的那些事

    Java线程池的那些事

    2015-08-19 00:00:00 出处:ImportNew
    分享

    熟悉java多线程的朋友一定十分了解java的线程池,jdk中的核心实现类为java.util.concurrent.ThreadPoolExecutor。大家可能了解到它的原理,甚至看过它的源码;但是就像我一样,大家可能对它的作用存在误解。现在问题来了,jdk为什么要提供java线程池?使用java线程池对于每次都创建一个新Thread有什么优势?

    对线程池的误解

    很长一段时间里我一直以为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线程池和创建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 减小单个线程的栈大小
    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。