利用线程池加速程序运行:从单线程948ms到多线程276ms的效率提升

内容简介

利用线程池加速程序运行:从单线程948ms到多线程276ms的效率提升

我最近与之接触的项目具有荒谬的数据,并且某些复杂的算法功能只是一场灾难。事不宜迟,以下是用于使用线程池来加快程序操作的示例参考。欢迎大家讨论并纠正它。

结果

直接将图片放置:

计算结果是相同的。计算时间仅为948ms。计算时间为276ms,使用4个线程池的螺纹,该线程的速度快四次甚至三倍!

完成代码

public static void main(String[] args) throws ParseException, InterruptedException, ExecutionException {
		// 初始化一个巨大数组,可以想象为我们需要处理的业务数据,上万甚至上亿条记录
        int[] a = new int[360000];
        // 随机放入100内随机数
        rand(a);
        long beginTime = System.currentTimeMillis();
        long b = 0L;
        // 传统单线程计算,10000*360000次运算,模拟对业务数据的处理过程
        for (int k = 0; k<10000 ; k++) {
            for (int i : a) {
                b += i;
            }
        }
        System.out.println("总和"+b);
        System.out.println("单独计算耗时"+(System.currentTimeMillis()-beginTime)+"毫秒");
        System.out.println("_______________________________________________________");
		// 使用线程池计算
        beginTime = System.currentTimeMillis();
        // 定义线程池,各参数含义可以看一下官方文档说明
        ExecutorService pool = new ThreadPoolExecutor(4,8,6
                ,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
        // 将业务数据切割为4份,分为4个线程处理,实际使用中可能不清楚数据量,用for循环就好
        // 此处子线程可用runable或callable,如果需要回调信息,则必须使用callable,返回值在自定义的线程类中编写
        Callable<Long> runnable = new sumThread(a,0,90000);
        Callable<Long> runnable1 = new sumThread(a,90000,180000);
        Callable<Long> runnable2 = new sumThread(a,180000,270000);
        Callable<Long> runnable3 = new sumThread(a,270000,360000);
        System.out.println("准备启动");
        // 四个线程初始化完成,提交给线程池
        Future<Long> num = pool.submit(runnable);
        Future<Long> num1 = pool.submit(runnable1);
        Future<Long> num2 = pool.submit(runnable2);
        Future<Long> num3 = pool.submit(runnable3);
        System.out.println("启动完成");
		// 调用callable的get()方法,从各子线程获取返回值,由于callable.get()方法特性,子线程运行完毕后才会调用这一行
        System.out.println("总和"+(num.get()+num1.get()+num2.get()+num3.get()));
        long endTime = System.currentTimeMillis();
        System.out.println("线程池总耗时"+(endTime-beginTime)+"毫秒");
        //关闭线程池,已提交的任务继续执行,不再接收新的任务
        pool.shutdown();
        //等待所有的任务都结束(实时判断是否全完成),若所有任务都已完成,则返回true,若超时未完成,则返回false
        if (!pool.awaitTermination(6, TimeUnit.SECONDS)) {
            //超时的时候向线程池中所有的线程发出中断(interrupted)。
            pool.shutdownNow();
        }
}
// 向数组中填充100内随机数
private static void rand(int[] a) {
	for (int i = 0; i < a.length; i++) {
        a[i] = new Random().nextInt(100);
    }
}
// 编写自定义线程类,可以实现runable或callable,如需调用返回值,则必须实现callable
class sumThread implements Callable<Long> {
	// 存放的业务数据
    int[] a ;
    // 定义一个返回值,可按需求修改
    long result;
    // 初始化线程实例时,从业务数据中根据下标取出 一小段数据
    public sumThread(int[] b,int start,int end) {
        a=Arrays.copyOfRange(b,start,end);
        System.out.println("初始化一个线程实例");
    }
	// 执行方法,模拟对业务数据的处理过程,运行完成后return指定的返回值
    @Override
    public Long call() throws Exception {
        System.out.println("启动一个线程");
        // a = rand1(a);
        long beginTime = System.currentTimeMillis();
        long b = 0L;
        for (int k = 0; k<10000 ; k++) {
            for (int j = 0; j < a.length; j++) {
                b += a[j];
            }
        }
        long endTime = System.currentTimeMillis();
        System.out.println("线程耗时"+(endTime-beginTime)+"毫秒");
        System.out.println("线程计算结果"+b);
        System.out.println("结束一个线程");
        result = b;
        return result;
    }
}

为什么线程池更快?

线程池提高程序操作效率的原理相对复杂。类比,如果将CPU核心与程序员进行比较(SAD),则单线线程就像程序员编写代码一样,而另一个项目经理和程序员正在喝茶和钓鱼。比较多线程,一位项目经理指示n个程序员同时编写代码。尽管项目经理(主线程)需要一些时间来创建工作站,举行会议来解释任务,并监督和管理项目进度,但n个人共同努力,比一个人单独进行项目更快。这也是线程处理时间的四个原因是单线处理时间的四分之一。 (当多汁的人工作时,他们也应该及时沟通。三个补鞋匠是最好的Zhuge Liang,而三位程序员至少是最佳的Feng Neumann)这也是“软件工程”的想法之一。您可以在日常生活中对此进行更多的思考。 “工程”的含义。

在实际的业务场景中,它比这要复杂得多,例如在处理业务数据后调用接口或从磁盘读取数据。 CPU速度比磁盘速度和网络速度快得多,这将导致程序的实际计算时间比空闲等待时间小得多。 CPU大部分时间都在吸吮。

另外,我想以程序员为例。小敏收到了一个工作单并写了业务功能A。完成代码(CPU操作)和5分钟的时间来编译和打包项目(检索接口)(有点夸张,但从计算机的角度来看, CPU计算速度比网络速度快得多),小敏基本上是在接下来的5分钟内等待茶。当然,我们希望小敏在接下来的5分钟内有事要做。第二天,小明将两台计算机放在他面前,并在汇编业务函数A时编写了业务功能B的守则B,并一遍又一遍地重复,这大大提高了时间利用率。

为什么建议将线程池用于多线程?每次直接写线程对我来说是否可以?

从功能实施的角度来看,这不是不可能的。但是据说,项目经理为程序员安排了任务,需要为他们提供工作站(创建新线程)。程序员的代码完成后,项目经理将拆除工作站(SAD),创建新的工作站和拆除工作站将消耗不必要的资源。线程池将保留这些空的工作站。线程池参数中的corepoolsize驻留核心线程定义了可以保留的电台数量。完成工作后,程序员仍将保留工作站。下次将有一项任务。只需坐下来工作以节省资源。通过调整线程池的其他参数,可以执行越来越多的精制调整和控制多线程程序。

使用多线程的目的是使程序更快并拥有更好的体验。由于使用线程池可以进一步节省资源并提高速度,为什么不呢?请记住,使用线池后,只需卸下不再使用的电台即可。

多线程随时更快吗?我可以没有大脑使用它吗?

当然,这不是,因为线程池需要管理和安排每个子线程,这也将消耗一定的时间和资源。如果数据量很小并且计算很简单,则使用多个线程实际上将拖动程序的运行速度。此外,无需使用如此多的技术将其通过简单的小数据功能(写代码也很累)来调整,这也是直觉。

当然,多线程用法方案仅限于不影响业务数据之间处理的方案:处理任何部分业务数据的处理不取决于其他部分的处理结果,或者没有严格的前端和 - 返回计算关系。就个人而言,我们倾向于对大量数据进行更重复和简单的操作。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

24阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

27阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

23阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读