如何仅使用单个线程检查多线程的性能?

问题描述

我正在研究 Java 多线程并尝试检查多线程的性能。我正在尝试检查多线程是否比单线程更好。 所以,我写了一个总和来限制的代码。 当限制变大时,它按我的预期工作(多线程比单线程快),但当限制像 100000L 一样小时却没有。 这是由于上下文切换吗?下面的代码是否适合检查多线程的性能

public class MultiThreadingSum {
    long count = 0;
    static long limit = 1000000000L;

    static void compareMultipleThreadToSingleThread(int threadCnt) {
        Runnable r = () -> {
            MultiThreadingSum mts = new MultiThreadingSum();
            long startTime = System.nanoTime();
            while(++mts.count<=limit);
            long endTime = System.nanoTime();
            long estimatedTime = endTime - startTime;
            double seconds = estimatedTime / 1000000000.0;

            System.out.println(Thread.currentThread().getName()+",elapsed time : "+seconds);
        };

        for(int i=0; i<threadCnt; i++) {
            new Thread(r,"multiThread"+i).start();
        }

        Runnable r2 = () -> {
            MultiThreadingSum mts = new MultiThreadingSum();
            long startTime = System.nanoTime();
            while(++mts.count<=limit*threadCnt);
            long endTime = System.nanoTime();
            long estimatedTime = endTime - startTime;
            double seconds = estimatedTime / 1000000000.0;

            System.out.println(Thread.currentThread().getName()+",elapsed time : "+seconds);
        };

        new Thread(r2,"singleThread").start();
    }

    public static void main(String[] args) {
        compareMultipleThreadToSingleThread(3);
    }
}

解决方法

在运行单线程实验之前,您的代码不会等待 3 线程实验完成。所以你可能会污染你的结果。

您的代码似乎不必要地复杂。我们不能分别运行两个单独的实验,一个有 3 个线程,一个有 1 个线程,以重用代码吗?

在现代 Java 中,我们很少需要处理 Thread 类。而是使用 Java 5 中添加的执行程序服务框架。

把这些放在一起,也许你的实验应该看起来更像下面这样。

警告:这只是一个非常粗略的剪裁,我还没想好,我的咖啡因已经用完了。所以仔细修改这段代码。也许我可以在一两天内修改这段代码。

package work.basil.threading;

import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Loopy
{
    public static void main ( String[] args )
    {
        Loopy app = new Loopy();

        List < Integer > inputThreadsLimit = List.of( 1,3,( Runtime.getRuntime().availableProcessors() - 1 ) );
        for ( Integer numberOfThreads : inputThreadsLimit )
        {
            System.out.println("----------|  Experiment for thread count: " + numberOfThreads + "  |--------------------------");
            Duration duration = app.demo( numberOfThreads ); // Waits here for the experiment to run to completion.
            System.out.println( numberOfThreads + " = " + duration + " total,each: " + duration.dividedBy( numberOfThreads ) );
        }
    }

    // Member fields
    final private AtomicInteger count = new AtomicInteger( 0 );

    private Duration demo ( final int numberOfThreads )
    {
        ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads );
        long start = System.nanoTime();
        for ( int i = 0 ; i < numberOfThreads ; i++ )
        {
            executorService.submit( new Task() );
        }
        executorService.shutdown();  // Ask the executor service to shutdown its backing pool of threads after all submitted tasks are done/canceled/failed.
        try { executorService.awaitTermination( 1,TimeUnit.HOURS ); } catch ( InterruptedException e ) { e.printStackTrace(); } // Tries to force the shutdown after timeout.

        Duration elapsed = Duration.ofNanos( System.nanoTime() - start );
        return elapsed;
    }

    class Task implements Runnable
    {
        @Override
        public void run ( )
        {
            int countSoFar = count.incrementAndGet();  // Thread-safe way to access,increment,and write a counter.
            // … add code here to do some kind of work …
            System.out.println( "Thread ID " + Thread.currentThread().getId() + " is finishing run after incrementing the countSoFar to: " + countSoFar + " at " + Instant.now() );
        }
    }
}
,

这不是一个很好的例子。多线程和单线程解决方案在同一个计数器上同时运行。所以实际上你用四个线程运行一个多线程进程。您需要运行一个解决方案,直到线程完成并关闭,然后再运行另一个。最简单的解决方案是在 main 方法中将单线程进程作为简单循环运行,并在循环完成后运行多线程解决方案。另外,我会有两个单独的计数器,或者,您可以在单线程循环完成后为计数器分配零