Java中使用线程池的效率对比和异步执行函数的参数问题

先说结论:

1,如果需要很多线程执行任务,每个任务都不大的话,用线程池性能提升很高,10几倍左右。

2,线程池开的线程不用太多,和机器cpu内核量差不多就行。

3,如果有函数是被异步调用执行的话,要注意给它传入的参数,可能在函数执行时并不是你当初预想的参数值。

-------------------------------------------------------------------------------------------------------------------------------

贴对比的代码:

public class TestMain {

static final int TNum=10000;

static int i=0;

//用线程池

public void UseThreadPool(int count) {

long startTime = System.currentTimeMillis();

ThreadPoolExecutor tp = new ThreadPoolExecutor(4, 8, 60, TimeUnit.SECONDS,

new LinkedBlockingQueue(count));

for (i= 0; i < count; i++) {

tp.execute(new Runnable() {

@Override

public void run() {

fun0( );

}

});

}

tp.shutdown();

try {

tp.awaitTermination(1, TimeUnit.DAYS);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.print("使用了线程池:");

System.out.println(System.currentTimeMillis() - startTime + "毫秒");

}

//不用线程池

public void unUseThreadPool(int count) {

long startTime = System.currentTimeMillis();

for ( i = 0; i < count; i++) {

Thread thread = new Thread() {

public void run() {

fun0();

}

};

thread.start();

try {

thread.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.print("未用线程池:");

System.out.println(System.currentTimeMillis() - startTime + "毫秒");

}

public static void main(String[] args) {

TestMain testpool = new TestMain();

testpool.UseThreadPool(TNum);

testpool.unUseThreadPool(TNum);

}

private Double fun0()

{

Random random = new Random();

String buf="abc"+random.nextDouble();

Double result=random.nextDouble()*random.nextDouble()*random.nextDouble();

int ak=0;

for (int i=1;i<100;i++)

{

ak=ak+i;

}

return result;

}

}

上面的代码线程池是4个线程,最多8个,执行后结果如下:

效果蛮好的,用了线程池性能提高10几倍。

我把线程池加大线程数量,到40个线程,最高80个,结果如下

这个和4线程差异不大,在变动范围内。

如果继续加大线程池开到4000个线程。则性能暴跌了

说明线程池的线程不用太对,估计只要和电脑cpu的核数量匹配就行。

----------------------------------------------------------------------------------------

然后,我想会不会是用了线程池后,线程没执行完就统计时间导致看起来性能高。

然后,我把上面的fun0()函数改了一下fun1:

private Double fun1(int par)

{

Random random = new Random();

String buf="abc"+random.nextDouble();

Double result=random.nextDouble()*random.nextDouble()*random.nextDouble();

int ak=0;

for (int i=1;i<100;i++)

{

ak=ak+i;

}

//if(par==(TNum-1))

{System.out.println("TNum:"+par);}

return result;

}

//用线程池的

for (i= 0; i < count; i++) {

{System.out.println("TNuma:"+(i+1));}

tp.execute(new Runnable() {

@Override

public void run() {

{System.out.println("TNumb:"+(i+1));}

fun1(i);

}

});

}

//不用线程池

for ( i = 0; i < count; i++) {

Thread thread = new Thread() {

public void run() {

//fun0();

fun1(i);

}

};

thread.start();

try {

thread.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

使用线程池的输出这样:

我原本希望fun1()收到的参数是0 1 2 3,但是看TNum的输出4个线程分别受到的参数是4 4 2 4。而从打印的TNuma 和TNumb的数据能看出,线程池里的线程是被异步执行的。正是因为线程池的execute()函数是异步的,它收到runnable后放入队列,所以for循环迅速执行完。

而线程池开始执行队列里的runnable的时候,才开始去调用fun1,并压入参数par,而这个时候i已经变了,并不是当初设想的0 1 2 3 了。

而未用线程池的输出是对的 

-------------------------------------------------------------------------------------

所以对于被异步调用执行的函数,对它的参数需要单独保存

我这样改了一下

class MyRunnable implements Runnable{

public int par;

public MyRunnable(int par)

{

this.par=par;

}

@Override

public void run() {

// TODO Auto-generated method stub

fun1(par);

}

}

然后

//线程池

for (i= 0; i < count; i++) {

tp.execute(new MyRunnable(i));

}

//未用线程池

for ( i = 0; i < count; i++) {

Thread thread = new Thread(new MyRunnable(i)) ;

thread.start();

try {

thread.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

这样参数就正常了


你可能感兴趣的:(Java中使用线程池的效率对比和异步执行函数的参数问题)