我是编程和Java的初学者,这是我的第一个多核程序。问题是我的程序从不使用超过13%的CPU。我不知道我是否以正确的方式做到了。
如何更快地计算并使用更多CPU资源?
我的课程包括三个课程:
使用多个线程实例化Work对象的"主类
A" T1"扩展Thread并包含要执行的工作的类
A"工作"启动所需线程号并显示所有线程执行工作所花费的时间的类
以下是我的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,但我没有找到问题的答案。
答案 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
}
}
}