线程没有没有线程版本快

时间:2011-10-18 22:14:15

标签: java multithreading

我知道还有其他问题,但我是初学者,大多数代码和问题都很复杂。这就是为什么我保持尽可能简单。我来自R背景,但最近我想了解更多有关Java线程的知识。我经历了几个关于这个主题的教程,其中大部分归结为我在下面发布的代码。请注意,代码没有做太多,我的效率非常低,因此线程会运行几秒钟。 需要注意的主要事情是,在我的机器上,线程的运行速度并不比无线程运行快。在run方法中for循环中的值较低,有时甚至更慢。这可能是因为我的硬件很糟糕(只有两个核心),而且有了更多内核,人们会看到线程比非并行版本更快。我不知道。但最令我困惑的是,当程序在两次运行(并行和非并行)运行时查看系统监视器时,使用两个核心,但在并行版本中,它们以接近100%运行并且非并行运行50 - 60%。考虑到两者同时完成并行版本的效率要低得多,因为它使用更多的计算机功能来执行相同的工作甚至更快。 简而言之。我究竟做错了什么?我以为我编写的程序与Java教程没有太大区别。我发布了以下链接。我使用sun版本的java运行linux ubuntu。

http://www.java2s.com/Tutorial/Java/0160__Thread/0020__Create-Thread.htm

import java.util.ArrayList;

public class Main { 
    public static void main(String[] args) {
        ArrayList<PermutateWord> words = new ArrayList<PermutateWord>();
        System.out.println(Runtime.getRuntime().availableProcessors());
        for(int i = 0; i < Runtime.getRuntime().availableProcessors();i++){
            words.add(new PermutateWord("Christoph"));
        }
        System.out.println("Run as thread");
        long d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.start();
        }
        for (PermutateWord w : words) {
            try {
                w.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
        System.out.println("No thread");
        d = System.currentTimeMillis();
        for (PermutateWord w : words) {
            w.run();
        }
        for (PermutateWord w : words) {
            System.out.println(w.getWord());
        }
        System.out.println(((double)(System.currentTimeMillis()-d))/1000+"\n");
    }
}
class PermutateWord extends Thread {    
    private String word;
    public PermutateWord (String word){
        this.word = word;
    }
    public void run() {
        java.util.Random rand = new java.util.Random();
        for(int i = 0; i <8000000;i++){
            word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
        }
    }
    private String swap(String word2, int r1, int r2) {
        char[] wordArray = word2.toCharArray();
        char c = wordArray[r1];
        wordArray[r1] = wordArray[r2];
        wordArray[r2] = c;
        return new String(wordArray);
    }
    public String getWord(){
        return word;
    }
}

提前致谢

了Christoph

2 个答案:

答案 0 :(得分:5)

大部分时间都是花费分配和处理临时字符串,必须同步。可以并行完成的工作是微不足道的,多线程不会给你带来太多好处。

Math.random()也必须同步。您将获得更好的结果,为每个线程创建本地java.util.Random

java.util.Random rand = new java.util.Random();

public void run() {
    for(int i = 0; i <8000000;i++){
        word = swap(word,rand.nextInt(word.length()), rand.nextInt(word.length()));
    }
}

但是,你应该专注于优化swap功能。我不确定,如果它能满足您的需求,但我确信它的效率非常低。 +上的String操作费用很高。对于每个+,JVM必须分配新的String,这对于多线程来说很慢并且不能很好地工作。如果您只想交换两个字符,请考虑使用char[]而不是String。它应该更容易,更快。

编辑:

private String swap(String word2, int r1, int r2) {
    char[] wordArray = word2.toCharArray();
    char c = wordArray[r1];
    wordArray[r1] = wordArray[r2];
    wordArray[r2] = c;
    return new String(wordArray);
}

这要好得多。但是,您仍在进行2次分配。 toCharArray()new String都分配内存。因为程序的其余部分非常简单,所以这两个分配占用了90%的执行时间。

答案 1 :(得分:0)

我在连接循环中放入Thread.sleep(1000)后得到了很多好处。 根据经验,java.util.Random.nextFloat()只给我买了10%。

即便如此,两部分机器在一台8芯机器上运行16秒,这表明它是 由于上面提到的同步而序列化。但好,悲伤,没有 它的睡眠速度慢了10倍。