【问题标题】:Why single thread is faster than multithreading in Java?为什么Java中单线程比多线程快?
【发布时间】:2013-11-22 23:49:34
【问题描述】:

据我了解,我在下面编写了简单的单线程和多线程程序来检查执行速度。但是我的单线程程序执行速度比多线程快,请看下面的程序,如果有什么问题请指出。

单线程:

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
穆尔 :::200000
穆尔 :::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 毫秒。那么多线程的真正目的是什么?

【问题讨论】:

  • “那么多线程的真正目的是什么?” - 有两个目的: 1. 避免长作业阻塞短作业(例如,在 Swing 应用程序中至少有两个线程,一个负责在屏幕上绘制什么,另一个负责对按钮做出反应点击;如果对按钮点击做出反应的线程也会在屏幕上绘制,则按钮不会对您点击它们做出反应或反应缓慢) 2.当有多个“处理单元”(多核/多处理器系统)时,JVM 可能将不同的线程分派到不同的单元,也许会加快速度。
  • 你在一个线程之后运行多线程 - 那个信息来自你输出的时间戳信息,而不是运行的持续时间。一些答案指出了这一点。

标签: java multithreading


【解决方案1】:

您所做的处理是微不足道的,因此创建线程的开销更昂贵。

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

【讨论】:

  • "如果您有可以并行完成的昂贵操作,那么多线程是有意义的。"谢谢,就是这样,我需要知道的
  • @Scary Wombat:你能定义“昂贵的操作”吗?您是指具有较大数字的乘法、加法等吗?
  • 昂贵的操作会涉及密集的数据库搜索/更新、I/O 或其他需要大量 CPU 的操作 - 例如用于分析的数字运算。简单的数学通常不会成为竞争者。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    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 次,并意识到每次得到完全不同的结果。这是因为测量准确的执行时间并非易事。操作系统会不断地用其他任务中断程序的执行,看似简单的命令可能会有一整串需要运行的后台命令。

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        如果您考虑一台处理器机器。所有线程都在单个处理器上运行。假设您的程序 (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?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-07-21
          • 2017-12-26
          • 1970-01-01
          • 2016-08-09
          • 1970-01-01
          • 2015-07-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多