Java 多线程程序没有使用很多 CPU
Java multi-threading programme not using a lot of CPU
我是编程初学者 Java,这是我的第一个多核程序。问题是我的程序从来没有使用超过 13% 的 CPU。不知道自己做的对不对
如何计算得更快并使用更多 CPU 资源?
我的程序包含三个class:
实例化Work对象的"mainclass线程数
扩展 Thread 并包含要执行的工作的 "T1" class
A "Work" class 启动所需的线程数并显示所有线程执行工作所花费的时间
这是我的代码 Main
class:
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);
}
这里是作品 class 代码:
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 class:
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,但我并没有真正找到问题的答案。
与其调用 Thread.run()
来实现您的线程所做的事情,不如调用 Thread.start()
,这将创建一个新线程并在该新线程上调用 run()
。
现在您 运行正在 run()
主线程上,而无需创建新线程。由于您有 13% CPU 负载,我预计您有 8 个内核(意味着您已完全填满一个内核)。
更好的方法是创建接口 Runnable
的自定义实现,而不是扩展 Thread
。然后你可以 运行 它在线程上如下:
Thread t = new Thread(new MyRunnableTask());
t.start();
这是常用方法,因为它使您可以灵活地(稍后)使用更高级的机制,例如 ExecutorService
。
编辑:
正如一些评论中所指出的那样。您还从多个线程更改了相同的变量(Work
中的静态变量)。你不应该这样做,因为它允许竞争条件。例如,如 here 所述,增加一个变量可能会导致一个变量。
谢谢大家回答我的问题:
是的,JVM不计算Math.cos(2.1545);在每次迭代中,正如我所说的那样,我已经尝试过 Math.cos(i);和原来的程序有很大的区别!
如前所述,对于多线程,我创建了接口 Runnable 的自定义实现,而不是扩展 Thread,现在使用 Start();方法而不是 运行();
我现在使用 join 方法等待线程完成并删除静态变量。
现在程序使用完整的 CPU 负载和正确的线程数。
仅供参考,这是我的工作新代码 class:
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 class:
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
}
}
}
我是编程初学者 Java,这是我的第一个多核程序。问题是我的程序从来没有使用超过 13% 的 CPU。不知道自己做的对不对
如何计算得更快并使用更多 CPU 资源?
我的程序包含三个class:
实例化Work对象的"mainclass线程数
扩展 Thread 并包含要执行的工作的 "T1" class
A "Work" class 启动所需的线程数并显示所有线程执行工作所花费的时间
这是我的代码 Main
class:
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);
}
这里是作品 class 代码:
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 class:
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,但我并没有真正找到问题的答案。
与其调用 Thread.run()
来实现您的线程所做的事情,不如调用 Thread.start()
,这将创建一个新线程并在该新线程上调用 run()
。
现在您 运行正在 run()
主线程上,而无需创建新线程。由于您有 13% CPU 负载,我预计您有 8 个内核(意味着您已完全填满一个内核)。
更好的方法是创建接口 Runnable
的自定义实现,而不是扩展 Thread
。然后你可以 运行 它在线程上如下:
Thread t = new Thread(new MyRunnableTask());
t.start();
这是常用方法,因为它使您可以灵活地(稍后)使用更高级的机制,例如 ExecutorService
。
编辑:
正如一些评论中所指出的那样。您还从多个线程更改了相同的变量(Work
中的静态变量)。你不应该这样做,因为它允许竞争条件。例如,如 here 所述,增加一个变量可能会导致一个变量。
谢谢大家回答我的问题:
是的,JVM不计算Math.cos(2.1545);在每次迭代中,正如我所说的那样,我已经尝试过 Math.cos(i);和原来的程序有很大的区别!
如前所述,对于多线程,我创建了接口 Runnable 的自定义实现,而不是扩展 Thread,现在使用 Start();方法而不是 运行();
我现在使用 join 方法等待线程完成并删除静态变量。 现在程序使用完整的 CPU 负载和正确的线程数。
仅供参考,这是我的工作新代码 class:
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 class:
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
}
}
}