当前位置:  开发笔记 > 编程语言 > 正文

Java线程创建开销

如何解决《Java线程创建开销》经验,为你挑选了2个好方法。

传统观点告诉我们,大批量企业Java应用程序应优先使用线程池来生成新的工作线程.使用java.util.concurrent使这简单明了.

但是,确实存在线程池不适合的情况.我目前正在努力的具体示例是使用InheritableThreadLocal,它允许ThreadLocal变量"传递"到任何生成的线程.使用线程池时,此机制会中断,因为工作线程通常不是从请求线程生成的,而是预先存在的.

现在有办法解决这个问题(线程本地可以显式传入),但这并不总是合适或实用.最简单的解决方案是按需生成新的工作线程,然后让它InheritableThreadLocal完成它的工作.

这让我们回到刚才的问题 - 如果我有一个高容量的网站,在这里用户请求的线程产卵关每个半打工作线程(即不使用线程池),这是怎么回事给JVM的一个问题?我们可能会谈论每秒创建几百个新线程,每个线程持续不到一秒钟.现代JVM是否能很好地优化这一点?我记得在Java中需要对象池的日子,因为对象创建很昂贵.从此变得不必要了.我想知道是否同样适用于线程池.

如果我知道要测量什么,我会对它进行基准测试,但我担心的是问题可能比用剖析器测量的更微妙.

注意:使用线程本地的智慧不是问题所在,所以请不要建议我不要使用它们.



1> Jaan..:

这是一个示例微基准测试:

public class ThreadSpawningPerformanceTest {
static long test(final int threadCount, final int workAmountPerThread) throws InterruptedException {
    Thread[] tt = new Thread[threadCount];
    final int[] aa = new int[tt.length];
    System.out.print("Creating "+tt.length+" Thread objects... ");
    long t0 = System.nanoTime(), t00 = t0;
    for (int i = 0; i < tt.length; i++) { 
        final int j = i;
        tt[i] = new Thread() {
            public void run() {
                int k = j;
                for (int l = 0; l < workAmountPerThread; l++) {
                    k += k*k+l;
                }
                aa[j] = k;
            }
        };
    }
    System.out.println(" Done in "+(System.nanoTime()-t0)*1E-6+" ms.");
    System.out.print("Starting "+tt.length+" threads with "+workAmountPerThread+" steps of work per thread... ");
    t0 = System.nanoTime();
    for (int i = 0; i < tt.length; i++) { 
        tt[i].start();
    }
    System.out.println(" Done in "+(System.nanoTime()-t0)*1E-6+" ms.");
    System.out.print("Joining "+tt.length+" threads... ");
    t0 = System.nanoTime();
    for (int i = 0; i < tt.length; i++) { 
        tt[i].join();
    }
    System.out.println(" Done in "+(System.nanoTime()-t0)*1E-6+" ms.");
    long totalTime = System.nanoTime()-t00;
    int checkSum = 0; //display checksum in order to give the JVM no chance to optimize out the contents of the run() method and possibly even thread creation
    for (int a : aa) {
        checkSum += a;
    }
    System.out.println("Checksum: "+checkSum);
    System.out.println("Total time: "+totalTime*1E-6+" ms");
    System.out.println();
    return totalTime;
}

public static void main(String[] kr) throws InterruptedException {
    int workAmount = 100000000;
    int[] threadCount = new int[]{1, 2, 10, 100, 1000, 10000, 100000};
    int trialCount = 2;
    long[][] time = new long[threadCount.length][trialCount];
    for (int j = 0; j < trialCount; j++) {
        for (int i = 0; i < threadCount.length; i++) {
            time[i][j] = test(threadCount[i], workAmount/threadCount[i]); 
        }
    }
    System.out.print("Number of threads ");
    for (long t : threadCount) {
        System.out.print("\t"+t);
    }
    System.out.println();
    for (int j = 0; j < trialCount; j++) {
        System.out.print((j+1)+". trial time (ms)");
        for (int i = 0; i < threadCount.length; i++) {
            System.out.print("\t"+Math.round(time[i][j]*1E-6));
        }
        System.out.println();
    }
}
}

在Intel Core2 Duo E6400 @ 2.13 GHz上使用32位Sun的Java 1.6.0_21客户端VM的64位Windows 7上的结果如下:

Number of threads  1    2    10   100  1000 10000 100000
1. trial time (ms) 346  181  179  191  286  1229  11308
2. trial time (ms) 346  181  187  189  281  1224  10651

结论:由于我的计算机有两个核心,因此两个线程的工作速度几乎是一个线程的两倍.我的计算机每秒可以生成近10000个线程,即线程创建开销为0.1毫秒.因此,在这样的机器上,每秒几百个新线程构成可忽略的开销(通过比较2和100个线程的列中的数字也可以看出).



2> Michael Borg..:

首先,这当然很大程度上取决于您使用的JVM.操作系统也将发挥重要作用.假设Sun JVM(嗯,我们还称它为吗?):

一个主要因素是分配给每个线程的堆栈内存,您可以使用-XssnJVM参数进行调整- 您将希望使用可以获得的最低值.

这只是一个猜测,但我认为"每秒几百个新线程"绝对超出了JVM设计的舒适性.我怀疑一个简单的基准测试会很快揭示出相当不容置妥的问题.


我发现`new Thread()`意味着什么是有趣的概念.在现代JVM中,`new Object()`并不总是分配新的内存,它重用以前的垃圾收集对象.我想知道是否有任何理由为什么JVM不能拥有一个隐藏的,可重用的线程内部池,因此`new Thread()`不一定会创建一个新的内核线程.您将获得有效的线程池,而无需使用API​​.
如果是这样的话,应该在一些JSR中找到它.可能是133 http://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf
推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有