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

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

作者: hexter | 来源:发表于2021-04-10 16:18 被阅读0次

    先说结论:

    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中使用线程池的效率对比和异步执行函数的参数问题

          本文链接:https://www.haomeiwen.com/subject/fljnkltx.html