测试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;
}}

解决方案 »

  1.   

    run 方法写得有点问题。第一,没加同步,这样算出来的count肯定不对。
    count++. 第一线程还没加一,满足条件的第2个线程也进来了,也+1,这样就加了两次,肯定不是你想要的数据。
    第2,给run加synchronized 后,还要把count的static去掉。因为count是类共享,第一个线程执行完毕,得到了count,第2个线程会在第一个count上接着加。
      

  2.   

    有几点1. 首先确认下这种情况下多线程是否真的比单线程高效2. 如果可工作线程数大于等于数组元素个数,那就每个线程各司其职,各自计算一个数组元素3. 否则还是要将具体的任务分配落实到具体每一个线程,这是为了避免重复工作4. 计数变量可以用AtomicInteger
      

  3.   

    并发计算任务,如果分成三个部分(数据准备,数据处理,结果合并),
    可以采用倒计时门栓技术来完成编程。
    思路清晰,简单。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(); 之后是结果合并。
      

  4.   


    很有意思的问题,不禁手痒,把你的代码修改了一下。解决了你原有的问题: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;
        }
    }
      

  5.   


    补充:执行输出示例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线程,效果有时更好!
      

  6.   

    简而言之,你就是想将某个问题分解为一定数量的子问题,为每一个问题分配一个线程来进行求解,之后在将所有的结果合并起来。典型的做法就是利用栅栏,这个你去google一把,例子一堆,就不举了
      

  7.   


    谢谢,这道题有三个版本,只是第一个版本,第二个版本 不是比0.5大 而是要比整个数组的平均值要大的为big number 第三个版本 不是返回count 而是要将第二个版本中所有的big number 以数组的方式返回。 我选择做了第一个版本。谢谢你的修改。