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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19901915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 21:11:22  来源:igfitidea点击:

Why single thread is faster than multithreading in Java?

javamultithreading

提问by Naveen

As of my understanding I have written the simple single and multithreading program below to check the execution speed. But my single-threaded program executing faster than multithreaded, kindly see the below program and mention if anything is wrong.

据我了解,我编写了下面的简单单线程和多线程程序来检查执行速度。但是我的单线程程序比多线程程序执行得更快,请参阅下面的程序并指出是否有任何问题。

Single Thread:

单线程:

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));
    }
}

Output:
Single Thread
Add :::1200
Sub :::800
Mul :::200000
Mul :::5
Calender - Time in milliseconds :138 415 866 7863

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


Multithreaded Program:


多线程程序:

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));
    }

}

Mulithreading Output:
Multithreading
Sub :::800
Division :::5
Add :::1200
Multiply :::200000
Calender - Time in milliseconds :138 415 868 0821


多线程输出:Multithreading
Sub :::800
Division ::5
Add ::1200
Multiply
:: 200000 Calender - 时间以毫秒为单位:138 415 868 0821

Here single thread executed at 138 415 866 7863 milliseconds and multithreading executed at this 138 415 868 0821 milliseconds. Then what is the real purpose of multithreading ?

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

回答by Scary Wombat

The processing that you are doing is trivial, so the overhead of creating threads is more expensive.

您正在执行的处理是微不足道的,因此创建线程的开销更昂贵。

If you had expensive operations which could be done in parallel then multi threads make sense.

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

回答by Sergey Morozov

First: Because the overhead of creating threads more, than the useful work performed by them.If you run more hard work in threads, it will make it faster than one thread.Trivial code must be runned in one thread.

第一:因为创建线程的开销比它们执行的有用工作要多。如果在线程中运行更多艰苦的工作,它将使其比一个线程更快。琐碎的代码必须在一个线程中运行。

Second: For creation micro-benchmark you should use JMH

第二:对于创建微基准,您应该使用JMH

回答by Peter

First of all, your time in miliseconds is just the timestamp. You need the difference in miliseconds between before and after the call in order to measure the elapsed time. I guess that you ran the single-threaded application first. If you try running the multi-threaded application first, you will notice that it has a lower "time in milliseconds"-value.

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

Second. Creating and managing threads has an overhead, which is far higher than the running time of the very simple arithmetic operations you perform. If you try to iterate the operations a few million times, you may see a performance gain by executing the operations in parallel.

第二。创建和管理线程的开销远远高于您执行的非常简单的算术运算的运行时间。如果您尝试迭代操作数百万次,您可能会看到并行执行操作带来的性能提升。

回答by TwoThe

1,384,158,667,863 milliseconds are about 44 years. So you are telling us that you waited 44 years on the result of this operation? Or could there be something wrong with the way you are measuring the speed of the execution?

1,384,158,667,863 毫秒大约是 44 年。所以你是说你等了 44 年才等到这个手术的结果?或者您测量执行速度的方式是否有问题?

To measure the difference between two times you need at least two times, while you only get the current date at the end of your program, which isn't even close to accurate.

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

Simple time measuring class:

简单的时间测量类:

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

Use this Stopwatch to measure the time for execution (like you would use a stopwatch), then do it 3 times and realize that each time you get entirely different results. This is because measuring exact execution time is not trivial at all. The OS constantly interrupts the execution of your program with other tasks and seemingly easy commands can have a whole chain of background commands that need to be run.

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

All you can do is to approximate the time it takes by running that task like a million times and then take the average.

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

回答by Houcem Berrayana

If you consider one processor machine. All the threads run on a single processor. let's suppose that your program (jvm) has 0.2 secs execution time on the processor every second. If you execute on a single thread, the 0.2 seconds will be dedicated only to this main thread. If you execute it on 4 threads for example the 0.2 seconds you will not have 0.05 + 0.05 + 0.05 + 0.05. You will need to add an extra time to synchronize, resume and dispose threads. If we suppose that this operation takes 0.001 seconds for every context switching. You will get 0.004 seconds of execution time lost every second provided that a thread executes once in a second. In real life thread context switching is made many times every second and it's unpredictable. Now things are changing as there are multicore machines and threads can execute at the same time on different cores.

如果您考虑一台处理器机器。所有线程都在单个处理器上运行。让我们假设您的程序 (jvm) 每秒在处理器上有 0.2 秒的执行时间。如果您在单个线程上执行,则 0.2 秒将仅专用于该主线程。如果您在 4 个线程上执行它,例如 0.2 秒,您将不会有 0.05 + 0.05 + 0.05 + 0.05。您将需要添加额外的时间来同步、恢复和处理线程。如果我们假设这个操作每次上下文切换需要 0.001 秒。如果线程每秒执行一次,您将每秒损失 0.004 秒的执行时间。在现实生活中,线程上下文切换每秒进行多次,而且是不可预测的。

Please see this link for more information: Does Java have support for multicore processors/parallel processing?

请参阅此链接了解更多信息:Java 是否支持多核处理器/并行处理?