测试JAVA并发编程算出一个double数组中大于0.5的数字的个数所用的时间(bigNums方法的英文注释就是题目要求)。下面是我的代码。main线程不是最后执行,会提前打印出 所以结果总是不对。我用join方法使得main线程最后执行也就失去了并发的意义了,而且最后的执行时间和单线程时一样。 有没有更好的算法,真正的并发,提高效率,使得执行时间最短!!!谢谢!public class BigNums extends Thread
{
private final double[] b; private final int from, to; private static int count; public BigNums(double[] b, int from, int to, String name)
{
super.setName(name); this.b = b; this.from = from; this.to = to;
} @Override
public void run()
{
for (int i = from; i < to; i++)
{
if (b[i] > 0.5)
{ count++; // System.out.println(this.getName() + " " + count); }
} } /**
* @param args
*/
public static void main(String[] args)
{
double[] list = new double[1 << 20]; for (int i = 0; i < list.length; i++)
{
list[i] = Math.random();
} long startTime = System.nanoTime(); int count = bigNums(list); long endTime = System.nanoTime(); System.out.println("Running time = " + ((endTime - startTime) / 1000)); System.out.println(count); } /**
* writing a parallel implementation of method bigNums below, using all
* available processors to maximum effect,returns a count of the number of
* "big" elements in b, where an element is defined to be big if it exceeds
* 0.5
*
* @param b
* @return
*/
static int bigNums(double[] b)
{ int procCount = Runtime.getRuntime().availableProcessors(); int n = b.length; int threadCount = procCount >= n ? n : procCount; int[] idx = new int[threadCount + 1]; for (int i = 0; i <= threadCount; i++)
{
idx[i] = (i * n) / threadCount;
} BigNums[] t = new BigNums[threadCount]; for (int i = 0; i < threadCount; i++)
{
t[i] = new BigNums(b, idx[i], idx[i + 1], "第" + i + "个"); t[i].start(); } // 下面注释代码为单线程测试使用的
// int count1 = 0;
//
// for(int i = 0; i < b.length; i++)
// {
// if(b[i] > 0.5)
// {
// count1++;
// }
// } return count;
}}
{
private final double[] b; private final int from, to; private static int count; public BigNums(double[] b, int from, int to, String name)
{
super.setName(name); this.b = b; this.from = from; this.to = to;
} @Override
public void run()
{
for (int i = from; i < to; i++)
{
if (b[i] > 0.5)
{ count++; // System.out.println(this.getName() + " " + count); }
} } /**
* @param args
*/
public static void main(String[] args)
{
double[] list = new double[1 << 20]; for (int i = 0; i < list.length; i++)
{
list[i] = Math.random();
} long startTime = System.nanoTime(); int count = bigNums(list); long endTime = System.nanoTime(); System.out.println("Running time = " + ((endTime - startTime) / 1000)); System.out.println(count); } /**
* writing a parallel implementation of method bigNums below, using all
* available processors to maximum effect,returns a count of the number of
* "big" elements in b, where an element is defined to be big if it exceeds
* 0.5
*
* @param b
* @return
*/
static int bigNums(double[] b)
{ int procCount = Runtime.getRuntime().availableProcessors(); int n = b.length; int threadCount = procCount >= n ? n : procCount; int[] idx = new int[threadCount + 1]; for (int i = 0; i <= threadCount; i++)
{
idx[i] = (i * n) / threadCount;
} BigNums[] t = new BigNums[threadCount]; for (int i = 0; i < threadCount; i++)
{
t[i] = new BigNums(b, idx[i], idx[i + 1], "第" + i + "个"); t[i].start(); } // 下面注释代码为单线程测试使用的
// int count1 = 0;
//
// for(int i = 0; i < b.length; i++)
// {
// if(b[i] > 0.5)
// {
// count1++;
// }
// } return count;
}}
count++. 第一线程还没加一,满足条件的第2个线程也进来了,也+1,这样就加了两次,肯定不是你想要的数据。
第2,给run加synchronized 后,还要把count的static去掉。因为count是类共享,第一个线程执行完毕,得到了count,第2个线程会在第一个count上接着加。
可以采用倒计时门栓技术来完成编程。
思路清晰,简单。package houlei.csdn.mutiThreads;import java.util.concurrent.CountDownLatch;/**
* 测试JAVA并发编程算出一个double数组中大于0.5的数字的个数所用的时间(bigNums方法的英文注释就是题目要求)。
*/
public class BigNums { static class Data{
double numbers[];
int result;//只用于校验的结果
}
static class Task{
double numbers[];
int start;
int end;
int count;//中间结果
}
static class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final Task task;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal , Task task) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.task = task;
} public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {
} // return;
} void doWork() {
for(int i=task.start;i<=task.end;i++){
if(task.numbers[i]>0.5)task.count++;
}
}
}
public static void main(String[] args) throws InterruptedException {
Data data = createData();
Task[] tasks = createTasks(data);
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(tasks.length);
for (int i = 0; i < tasks.length; ++i){ // create and start threads
new Thread(new Worker(startSignal, doneSignal, tasks[i])).start();
}
long startTime = System.nanoTime();
startSignal.countDown(); // let all threads proceed
doneSignal.await(); // wait for all to finish
int count = 0; // result count
for(int i=0;i<tasks.length;i++){
count += tasks[i].count;
}
long endTime = System.nanoTime();
System.out.println("Running time = " + ((endTime - startTime) / 1000));
System.out.println(data.result+" = "+count);
} private static Task[] createTasks(Data data) {
int procCount = Runtime.getRuntime().availableProcessors();
int threadCount = procCount >= data.numbers.length ? data.numbers.length : procCount;
Task[] tasks = new Task[threadCount];
int a = data.numbers.length/threadCount,b=data.numbers.length%threadCount;
int index = 0;
for(int i=0;i<tasks.length;i++){
tasks[i] = new Task();
tasks[i].numbers = data.numbers;
tasks[i].start=index;
index+=a;
if(i<b){
index++;
}
tasks[i].end=index-1;
}
return tasks;
} private static Data createData() {
double[] list = new double[1 << 20];
int count = 0;
for (int i = 0; i < list.length; i++) {
list[i] = Math.random();
if(list[i]>0.5)count++;
}
Data data = new Data();
data.numbers = list;
data.result = count;
return data;
}}其中, startSignal.countDown(); 之前是数据准备;doneSignal.await(); 之后是结果合并。
很有意思的问题,不禁手痒,把你的代码修改了一下。解决了你原有的问题:What's new?
1, 解决了线程同步的问题。这样,main线程会最后执行,不会提前打印。结果运算正确;(7楼)
2,证明了多线程运算,快于单线程。注释:数组的长度要大于“1<<22”, "1<<25" 最好!小了看不出多线程运算的优越性,这是由于下面的原因:
1)线程 scheduling 的 overhead(一般性问题);
2)所有线程都读取同一个内存数组,而读取内存不一定是并列运行的。
3)运算 b[i] > 0.5 太简单,读取内存的时间与运算时间相差不大。
这些说明了,这道题出得不合理,不适合多线程运算。
改进题目本身的方法是:加重运算对 cpu 的依赖,比如改为
b[i]=Math.exp(b[i]); // heave double calculation
b[i]=Math.log(b[i]);
if (b[i]>0.5) {};
的话,即使数组长度不大,也可以看出效果。
/**
* 2013-03-27
* @author of first edition: followme_1987
* @author of second edition: jswatcher at csdn.net
* improved with thread synchronization
*/
public class BigNums extends Thread
{
private final double[] b;
private final int from, to;
private static int count;
// 新导入变量,用于 synchronization
private static Object sync = new Object();
private static int runningThreads;
public BigNums(double[] b, int from, int to, String name)
{
super.setName(name);
this.b = b;
this.from = from;
this.to = to;
} @Override
public void run()
{
int count1 = 0;
for (int i = from; i < to; i++)
{
if (b[i] > 0.5)
{
count1++;
}
} synchronized (sync) {
System.out.println(this.getName() + " count: " + count1 + " in total " + (to - from));
count += count1;
// 通知主线程,运算结束
runningThreads--;
sync.notify();
}
} /**
* @param args
*/
public static void main(String[] args)
{
//注意:数组长度要大于 1<<22,小了看不出差距
double[] list = new double[1 << 22]; for (int i = 0; i < list.length; i++)
{
list[i] = Math.random();
} long startTime,endTime;
int count; int procCount = Runtime.getRuntime().availableProcessors();
int threadCount = procCount >= list.length ? list.length : procCount;
//threadCount = (threadCount>>1); // 用一半线程,因为 Hyperthread
// 测试多线程
System.out.println("" + threadCount + "线程: 运算开始");
startTime = System.nanoTime();
count = bigNums(list, threadCount);
endTime = System.nanoTime();
System.out.println("结果:Count: " + count + " in total " + list.length);
System.out.println("" + threadCount + "线程: Running time = " + ((endTime - startTime) / 1000)); System.out.println();
// 测试单线程
System.out.println("单线程: 运算开始");
startTime = System.nanoTime();
count = bigNums(list, 1);
endTime = System.nanoTime();
System.out.println("结果:Count: " + count + " in total " + list.length);
System.out.println("单线程: Running time = " + ((endTime - startTime) / 1000));
} /**
* writing a parallel implementation of method bigNums below, using all
* available processors to maximum effect,returns a count of the number of
* "big" elements in b, where an element is defined to be big if it exceeds
* 0.5
*
* @param b
* @param threadCount
* @return
*/
static int bigNums(double[] b, int threadCount)
{
if ( threadCount > 1 ) {
int n = b.length;
int[] idx = new int[threadCount + 1];
for (int i = 0; i <= threadCount; i++)
{
idx[i] = (i * n) / threadCount;
} BigNums[] t = new BigNums[threadCount];
runningThreads = threadCount;
for (int i = 0; i < threadCount; i++)
{
t[i] = new BigNums(b, idx[i], idx[i + 1], "第" + i + "个");
t[i].start(); // 工作线程开始
}
// 主线程:等待所有线程结束 ( runningThreads == 0 )
synchronized (sync) {
while ( runningThreads > 0 ) { // 检查工作线程数
try {
sync.wait(10000);
} catch (InterruptedException e) {
}
}
}
} else {
// 下面注释代码为单线程测试使用的
count = 0;
for (int i = 0; i < b.length; i++) {
if (b[i] > 0.5) {
count++;
}
}
} return count;
}
}
补充:执行输出示例8线程: 运算开始
第4个 count: 262171 in total 524288
第3个 count: 262033 in total 524288
第2个 count: 261454 in total 524288
第5个 count: 262866 in total 524288
第0个 count: 262622 in total 524288
第1个 count: 262192 in total 524288
第6个 count: 262271 in total 524288
第7个 count: 261968 in total 524288
结果:Count: 2097577 in total 4194304
8线程: Running time = 10139单线程: 运算开始
结果:Count: 2097577 in total 4194304
单线程: Running time = 20757
注释:由于 inter hyperthread 的缘故,实际的 processor 数通常是表示的一半。我的机子上,如果是4线程,效果有时更好!
谢谢,这道题有三个版本,只是第一个版本,第二个版本 不是比0.5大 而是要比整个数组的平均值要大的为big number 第三个版本 不是返回count 而是要将第二个版本中所有的big number 以数组的方式返回。 我选择做了第一个版本。谢谢你的修改。