为什么单线程比Java中的多线程更快?

时间:2013-11-11 08:32:29

标签: java multithreading

据我了解,我已经编写了下面简单的单线程和多线程程序来检查执行速度。但我的单线程程序执行速度比多线程快,请看下面的程序并提出是否有错误。

单线程:

import java.util.Calendar;

public class NormalJava {
    public static void main(String[] args) {
        System.out.println("Single Thread");
        int a = 1000;
        int b = 200;
        NormalJava nj = new NormalJava();
        nj.Add(a, b);
        nj.Sub(a, b);
        nj.Mul(a, b);
        nj.Div(a, b);
        Calendar lCDateTime = Calendar.getInstance();
        System.out.println("Calender - Time in milliseconds :"
                + lCDateTime.getTimeInMillis());

    }

    private void Add(int a, int b) {
        System.out.println("Add :::" + (a + b));
    }

    private void Sub(int a, int b) {
        System.out.println("Sub :::" + (a - b));
    }

    private void Mul(int a, int b) {
        System.out.println("Mul :::" + (a * b));
    }

    private void Div(int a, int b) {
        System.out.println("Mul :::" + (a / b));
    }
}

输出:
    单线程
    添加::: 1200
    子::: 800
    Mul ::: 200000
    Mul ::: 5
    日历 - 以毫秒为单位的时间:138 415 866 7863


多线程程序:

package runnableandcallable;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class MainThread {

    private static ExecutorService service = Executors.newFixedThreadPool(10); // connection
                                                                               // pool
    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Multithreading");
        MainThread mt = new MainThread();
        mt.testThread(1000, 200);
        Calendar lCDateTime = Calendar.getInstance();
        System.out.println("Calender - Time in milliseconds :"
                + lCDateTime.getTimeInMillis());
    }

    public void testThread(final int a, final int b) {
        // create a callable for each method
        Callable<Void> callableAdd = new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Add(a, b);
                return null;
            }
        };

        Callable<Void> callableSub = new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Sub(a, b);
                return null;
            }
        };

        Callable<Void> callableMul = new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Mul(a, b);
                return null;
            }
        };

        Callable<Void> callableDiv = new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Div(a, b);
                return null;
            }
        };

        // add to a list
        List<Callable<Void>> taskList = new ArrayList<Callable<Void>>();
        taskList.add(callableAdd);
        taskList.add(callableSub);
        taskList.add(callableMul);
        taskList.add(callableDiv);

        // create a pool executor with 3 threads
        ExecutorService executor = Executors.newFixedThreadPool(3);

        try {
            // start the threads
            List<Future<Void>> futureList = executor.invokeAll(taskList);

            for (Future<Void> voidFuture : futureList) {
                try {
                    // check the status of each future. get will block until the
                    // task
                    // completes or the time expires
                    voidFuture.get(100, TimeUnit.MILLISECONDS);
                } catch (ExecutionException e) {
                    System.err
                            .println("Error executing task " + e.getMessage());
                } catch (TimeoutException e) {
                    System.err.println("Timed out executing task"
                            + e.getMessage());
                }

            }

        } catch (InterruptedException ie) {
            // do something if you care about interruption;
        }

    }

    private void Add(int a, int b) {
        System.out.println("Add :::" + (a + b));
    }

    private void Sub(int a, int b) {
        System.out.println("Sub :::" + (a - b));
    }

    private void Mul(int a, int b) {
        System.out.println("Multiply :::" + (a * b));
    }

    private void Div(int a, int b) {
        System.out.println("Division :::" + (a / b));
    }

}

多线程输出:
    多线程
    子::: 800
    师::: 5
    添加::: 1200
    乘::: 200000
    日历 - 以毫秒为单位的时间:138 415 868 0821

这里单线程执行138 415 866 7863毫秒,多线程执行138 415 868 0821毫秒。那么多线程的真正目的是什么?

5 个答案:

答案 0 :(得分:34)

您正在进行的处理非常简单,因此创建线程的开销更加昂贵。

如果你有可以并行完成的昂贵操作,那么多线程就有意义了。

答案 1 :(得分:8)

<强>第一: 因为创建线程的开销比它们执行的有用工作更多。如果你在线程中运行更多的工作,它将使它比一个线程更快。必须在一个线程中运行必须代码。

<强>第二: 对于创建微基准测试,您应该使用JMH

答案 2 :(得分:6)

1,384,158,667,863毫秒约为44年。所以你告诉我们你等了44年这次行动的结果?或者测量执行速度的方式可能有问题吗?

要测量两次之间的差异,至少需要两次,而你只得到程序结束时的当前日期,这甚至不准确。

简单时间测量课程:

public class StopWatch {
  private long startTime = -1;

  public void start() {
    this.startTime = System.nanoTime();
  }

  public long timeNanos() {
    return System.nanoTime() - this.startTime;
  }

  public double timeMillis() {
    return this.timeNanos() / 1000000.0;
  }
}

使用此秒表来测量执行时间(就像使用秒表一样),然后进行3次,并意识到每次获得完全不同的结果。这是因为测量精确的执行时间根本不是微不足道的。操作系统不断地用其他任务中断程序的执行,看似简单的命令可以有一整套需要运行的后台命令。

您所能做的就是通过运行该任务一百万次来估算所需的时间,然后取平均值。

答案 3 :(得分:3)

首先,你以毫秒为单位的时间只是时间戳。您需要在调用之前和之后的毫秒差异,以便测量经过的时间。我想你先运行单线程应用程序。如果您尝试首先运行多线程应用程序,您会注意到它具有较低的“毫秒时间”值。

二。创建和管理线程会产生开销,这远远高于您执行的非常简单的算术运算的运行时间。 如果您尝试将操作迭代几百万次,则可以通过并行执行操作来获得性能提升。

答案 4 :(得分:2)

如果考虑一台处理器计算机。所有线程都在单个处理器上运行。让我们假设你的程序(jvm)每秒在处理器上有0.2秒的执行时间。 如果在单个线程上执行,则0.2秒将仅专用于此主线程。 如果你在4个线程上执行它,例如0.2秒,你就不会有0.05 + 0.05 + 0.05 + 0.05。您将需要额外的时间来同步,恢复和处置线程。如果我们假设每次上下文切换这个操作需要0.001秒。如果线程在一秒钟内执行一次,则每秒会丢失0.004秒的执行时间。 在现实生活中,线程上下文切换每秒进行多次,并且它是不可预测的。 现在情况正在发生变化,因为有多核机器和线程可以在不同的核心上同时执行。

请参阅此链接以获取更多信息:Does Java have support for multicore processors/parallel processing?