基本Java线程(4个线程)比非线程慢

基本Java线程(4个线程)比非线程慢,java,multithreading,concurrency,parallel-processing,Java,Multithreading,Concurrency,Parallel Processing,我有一个四核CPU。我创建了4个线程并运行了一个cpu密集型循环,比在一个线程中运行所有线程所需的时间长4倍以上 我创建了两个项目进行比较,一个有线程,一个没有线程。我将显示代码和运行时间。请注意,没有线程的项目看起来很奇怪的原因是我想复制内存开销,因为我不确定它会对运行时产生多大影响。下面是不带线程的代码: class TimeTest implements Runnable { private Thread t; private String name; TimeT

我有一个四核CPU。我创建了4个线程并运行了一个cpu密集型循环,比在一个线程中运行所有线程所需的时间长4倍以上

我创建了两个项目进行比较,一个有线程,一个没有线程。我将显示代码和运行时间。请注意,没有线程的项目看起来很奇怪的原因是我想复制内存开销,因为我不确定它会对运行时产生多大影响。下面是不带线程的代码:

class TimeTest implements Runnable {
    private Thread t;
    private String name;

    TimeTest(String name) {
        this.name = name;
        System.out.println("Creating class " + name);
    }

    public void run() {
        System.out.println("Running class " + name);

        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Class " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Class " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting class " + name);

        if (t == null) {
            t = new Thread(this, name);
//            t.start();
            this.run();
        }
    }
}

public class ThreadComp {
    public static void main(String[] args) {
        TimeTest one = new TimeTest("Class-1");
        one.start();

        TimeTest two = new TimeTest("Class-2");
        two.start();

        TimeTest three = new TimeTest("Class-3");
        three.start();

        TimeTest four = new TimeTest("Class-4");
        four.start();
    }
}
class RunnableTest implements Runnable {
    private Thread t;
    private String name;

    RunnableTest(String name) {
        this.name = name;
        System.out.println("Creating thread " + name);
    }

    public void run() {
        System.out.println("Running thread " + name);
        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Thread " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Thread " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting thread " + name);

        if (t == null) {
            t = new Thread(this, name);
            t.start();
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        RunnableTest one = new RunnableTest("Thread-1");
        one.start();

        RunnableTest two = new RunnableTest("Thread-2");
        two.start();

        RunnableTest three = new RunnableTest("Thread-3");
        three.start();

        RunnableTest four = new RunnableTest("Thread-4");
        four.start();
    }    
}
这大约需要11秒钟

以下是有关线程的代码:

class TimeTest implements Runnable {
    private Thread t;
    private String name;

    TimeTest(String name) {
        this.name = name;
        System.out.println("Creating class " + name);
    }

    public void run() {
        System.out.println("Running class " + name);

        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Class " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Class " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting class " + name);

        if (t == null) {
            t = new Thread(this, name);
//            t.start();
            this.run();
        }
    }
}

public class ThreadComp {
    public static void main(String[] args) {
        TimeTest one = new TimeTest("Class-1");
        one.start();

        TimeTest two = new TimeTest("Class-2");
        two.start();

        TimeTest three = new TimeTest("Class-3");
        three.start();

        TimeTest four = new TimeTest("Class-4");
        four.start();
    }
}
class RunnableTest implements Runnable {
    private Thread t;
    private String name;

    RunnableTest(String name) {
        this.name = name;
        System.out.println("Creating thread " + name);
    }

    public void run() {
        System.out.println("Running thread " + name);
        int value = 100000000;
//        try {
            while (--value > 0) {
                Math.random();
//                Thread.sleep(1);
//                System.out.println("Thread " + name + " " + value);
            }
//        } catch (InterruptedException e) {
//            System.out.println("Interrupted " + name);
//        }

        System.out.println("Thread " + name + " exiting...");
    }

    public void start() {
        System.out.println("Starting thread " + name);

        if (t == null) {
            t = new Thread(this, name);
            t.start();
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        RunnableTest one = new RunnableTest("Thread-1");
        one.start();

        RunnableTest two = new RunnableTest("Thread-2");
        two.start();

        RunnableTest three = new RunnableTest("Thread-3");
        three.start();

        RunnableTest four = new RunnableTest("Thread-4");
        four.start();
    }    
}
这大约需要1分13秒

现在,在我学习的示例中,他们在50毫秒的引导期间调用Thread.sleep。如果我这样做,如果我在非线程类上调用Thread.sleep(50),线程运行得更快

这很好,我知道如何让它工作。但我学习这一点的原因是我正在进行寻路,我不打算在已经需要很长时间、甚至1毫秒都不需要暂停和什么都不做的事情上添加睡眠呼叫(除非它绝对必须这样做)

所以,我想知道的是我错过了什么?线程是否必须完全处于休眠状态,或者对象是否必须等待线程按照我的意愿工作(即并行运行所有四个循环)


即使我只是犯了个错误,为什么要花这么长时间?我认为最坏的情况是,它仍将在11秒内运行,它将以某种不可预见的顺序完成….

执行时间的巨大差异是由
Math.random()
方法造成的。如果深入研究它的实现,您会发现它使用了所有线程共享的静态
randomNumberGenerator
。如果再深入一步,您会注意到执行依赖于
intnext(int)
方法,该方法依次使用
Random.seed
,即
AtomicLong
(请考虑所有线程都使用相同的
Random
!)。现在我们要讨论的是原子长,它是通过实现的,这就是问题所在。乐观锁不是为高负载设计的,当多个线程试图同时访问它们时,它们会受到很大的影响,这就是您所观察到的性能下降


TL;DR:使用(感谢@bayou.io提到这一点)并享受性能提升

您的问题是您正在使用。关于此方法的文档:

此方法已正确同步,以允许多个线程正确使用但是,如果许多线程需要以很快的速度生成伪随机数,则可能会减少每个线程拥有自己的伪随机数生成器的争用。

(强调矿山)


因此,解决方案是为每条线程创建一个新的
Random

因此-需要4名妇女36个月才能生下一个孩子?我几乎可以保证,使用
Math.Random
是这个问题的原因。看看@JAtkin说了些什么。你的代码基本上都是锁争用的。@bayou.io-我想你的意思是问9名女性是否需要1个月才能生下一个孩子…ThreadLocalRandom-就是这样。如果没有线程,1999000000 nextFloat()s需要5秒。使用线程2(ed:实际上5秒可能是侥幸)秒。事实上,这让我很惊讶,因为我认为四个人完成这项任务仍然需要5秒钟。但我要了。我之所以选择Math.random(),是因为我需要一些开销足够大的东西,但担心打印到控制台会迫使它返回到一个线程。无论如何,谢谢。