Java多线程程序没有使用大量的CPU

时间:2015-09-21 07:41:36

标签: java multithreading performance cpu-usage

我是编程和Java的初学者,这是我的第一个多核程序。问题是我的程序从不使用超过13%的CPU。我不知道我是否以正确的方式做到了。

如何更快地计算并使用更多CPU资源?

我的课程包括三个课程:

  1. 使用多个线程实例化Work对象的"主类

  2. A" T1"扩展Thread并包含要执行的工作的类

  3. A"工作"启动所需线程号并显示所有线程执行工作所花费的时间的类

  4. 以下是我的Main课程的代码:

    public static void main(String[] args) {
    
      System.out.println("Number of CPUs available = " + Runtime.getRuntime().availableProcessors()); //Display the number of CPUs available
      int iteration = 100000000; // Define a number of itterations to do by all threads
    
      /*
      Instantiates each work with a different number of threads (1, 4, 8, 12, and 24)
      */
        Work  t1 = new Work(1);
        Work  t4 = new Work(4);
        Work  t8 = new Work(8);
        Work t12 = new Work(12);
        Work t24 = new Work(24);
    
    
       /*
        Launch the work for each thread with the specified number of iterations
        */
        t1.goWork(iteration);
        t4.goWork(iteration);
        t8.goWork(iteration);
        t12.goWork(iteration);
        t24.goWork(iteration);
    
        }
    

    这里的工作类代码:

    public class Work {
    
        static long time;     // A variable that each thread increase by the time it takes to complete its task.
        static int itterationPerThread;      // A variable that stores the number of itterations Per Thread to do.
        static int finish;     // A variable that each thread incrase when it finish its task, used to wait until all thread has complete their task.
        private int numberOfThreads;     // The number of threads to launch.
        /**
         *
         * The constructor, set the number Of threads to run
         * @param numberOfThreads
         */
        public Work(int numberOfThreads)
        {
            this.numberOfThreads = numberOfThreads;   //Set the number of threads
        }
    
        /**
         *
         * A method that launch a specified number of thread in the constructor of the class, and distributes the a number of iteration of each thread.
         * The method does nothing until each thread completes its task and print the time needed for all threads to complete their tasks.
         * @param itterationPerThread
         */
        public void goWork(int itterationPerThread)
        {
            finish = 0;   //Reset the variable in the case that we call the method more than one time
            time = 0;    //Reset the variable in the case that we call the method more than one time
            this.itterationPerThread = itterationPerThread/numberOfThreads;   // Divide the given number of iterations by the number of threads specified in the constructor
    
            for (int i=0; i<numberOfThreads; i++)   //Launch the specified number of threads
            {
                  new T1().run();
            }
    
            while (finish != numberOfThreads)    //Do nothing until all thread as completed their task
            {
            }
            System.out.println("Time for " + numberOfThreads + " thread = " + time + " ms");   //Display the total time
        }
    
    }
    

    最后我的T1班:

    public class T1 extends Thread{
    
        @Override
        public void run()
        {
            long before = System.currentTimeMillis();
    
            for (int i=0; i<Work.itterationPerThread; i++) //Get the thread busy with a number of itterations
            {
                Math.cos(2.1545); //Do something...
            }
    
             long after = System.currentTimeMillis(); //Compute the elapsed time
             Work.time += after - before; //Increase the static variable in Work.java by the time elapsed for this thread
             Work.finish++; // Increase the static variable in Work.java when the thread has finished its job
        }
    }
    

    该程序在我的机器上给出了以下输出(四个物理核心和八个超线程):

    可用的CPU数量= 8

    1个线程的时间= 11150毫秒

    4线程的时间= 4630毫秒

    8线程的时间= 2530毫秒

    12个线程的时间= 2530毫秒

    24线程的时间= 2540毫秒

    根据我的CPU,这个结果似乎是正确的,但我的CPU使用率从未超过13%。

    我找到了以下Stack Overflow post,但我没有找到问题的答案。

2 个答案:

答案 0 :(得分:7)

您应该调用Thread.run()而不是调用Thread.start()来实现您的线程所做的事情,而run()将创建一个新线程并在该新线程上调用run()

现在您在主线程上运行Runnable,而没有创建新线程。由于你有13%的CPU负载,我希望你有8个核心(意味着你已经完全填充了一个核心)。

更好的方法是创建接口Thread的自定义实现,而不是扩展Thread t = new Thread(new MyRunnableTask()); t.start(); 。然后,您可以在线程上运行它,如下所示:

ExecutorService

这是常用的方法,因为它为您提供了灵活性(稍后)使用更高级的机制,例如Work

编辑: 正如一些评论中所指出的那样。您还要从多个线程更改相同的变量(Is Active中的静态变量)。你永远不应该这样做,因为它允许竞争条件。例如,递增变量可能会导致变量here

答案 1 :(得分:0)

谢谢大家回答我的问题:

是的,JVM不计算Math.cos(2.1545);在每次迭代中,所以我已经尝试过使用Math.cos(i);在原始程序上有很大的不同!

对于多线程,如上所述,我已经创建了Runnable接口的自定义实现,而不是扩展Thread而现在使用Start();方法而不是run();

我现在使用join方法等待线程完成并删除静态变量。 现在程序使用具有正确线程数的完整CPU负载。

仅供参考,以下是我的工作类新代码:

public class Work {

    private Thread[] threadArray; //An array to store a specified number of new threads in the constructor
    /**
     *
     * The constructor, set to the number Of threads to run
     * @param numberOfThreads
     */
    public Work(int numberOfThreads)
    {

        threadArray = new Thread[numberOfThreads];
    }

    /**
     *
     * A methode that launch a specified number of threads in the constructor of the class, and distributes the a number of iteration of each thread.
     * the methode wait until each thread complete their task and print the time needed for all thread to complette their task.
     * @param itterationForAllThread   --> the total of itteration to do by all thread
     */
    public void goWork(int itterationForAllThread)
    {
        long time = 0; // A variable used to compute the elapsed time
        int itterationPerThread; // A variable that store the number of itterations Per Thread to do
        itterationPerThread = itterationForAllThread/threadArray.length; //Divide the given number of itteration by the number of tread specified in the constructor

        for(int i=0; i<threadArray.length; i++) //Launch the specified number of threads
        {
              threadArray[i] = new Thread(new T1(itterationPerThread));  //Create a new thread
              threadArray[i].start();  //Start the job
        }

        long before = System.currentTimeMillis();

        for (Thread thread : threadArray) //For each thread wait until it finish
        {
            try {
                 thread.join(); //Wait for the thread as finish
            }
            catch (InterruptedException ex)
            {
                ex.printStackTrace();
            }
        }
        long after = System.currentTimeMillis();
        time = after - before; //Compute the time elapsed

        System.out.println("Time for " + threadArray.length + " Thread = " + time + " ms"); //Display the total time for the number of threads
    }
}

这里是T1班:

public class T1 implements Runnable{

    private int iterrattionPerThread;

    T1(int iterrattionPerThread)
    {
        this.iterrattionPerThread=iterrattionPerThread;
    }


    @Override
    public void run()
    {
        for(int i=0; i<iterrattionPerThread; i++) //Get the thread busy with a number of iterations
        {
            Math.cos(i); //Do something that the JVM can not cache and need to be recaculated every iteration
        }
    }
}