ExecutorService 添加延迟

ExecutorService adding delay

我有一个使用 ExecutorService 的非常简单的程序。

我设置了号码。线程数为 4,但所用时间与设置为 2 相同。

下面是我的代码:

public class Test {
     private static final Logger LOGGER = Logger.getLogger("./sample1.log");

    @SuppressWarnings("unchecked")
    public static void main(String[] args) throws Throwable {
        ExecutorService service = Executors.newFixedThreadPool(4);
        Future<String> resultFirst = service.submit(new FirstRequest());
        Future<String> resultSecond = service.submit(new SecondRequest());
        Future<String> resultThird = service.submit(new ThirdRequest());
        Future<String> resultFourth = service.submit(new FourthRequest());

        String temp1 = resultSecond.get();
        temp1 = temp1.replace("Users", "UsersAppend1");

        String temp2 = resultThird.get();
        temp2 = temp2.replace("Users", "UsersAppend2");

        String temp3 = resultFourth.get();
        temp3 = temp3.replace("Users", "UsersAppend3");

        //System.out.println(resultFirst.get() + temp1 + temp2 + temp3);
        //LOGGER.info("Logger Name: "+LOGGER.getName());

        LOGGER.info(resultFirst.get() + temp1 + temp2 + temp3);

        service.shutdownNow();
        service.awaitTermination(10, TimeUnit.SECONDS);

        System.exit(0);
        }
}

这里的 FirstRequest、SecondRequest、ThirdRequest 和 FourthRequest 是不同的 classes,它们调用另一个 class,这是所有人都共有的。

我已经为常见的 class 创建了不同的对象,所以我认为这不是 deadlock/Starvation 的情况。

您想开始 here - 意思是:实际上 很难 以合理的方式测量 Java 执行时间。很可能您的观点过于简单化;因此您的测量值没有说明任何问题。

除此之外:您必须了解 "more threads" 不会神奇地减少整体运行时间。这在很大程度上取决于您在做什么;以及例如您的线程花费时间等待 IO 的频率。

含义:"adding" 个线程仅在每个线程在 "longer" 时间段内处于非活动状态时才有帮助。当每个线程都以 100% 的速度持续燃烧 CPU 个循环时……那么更多的线程也无济于事;相反:情况会变得更糟,因为您唯一要做的就是增加 开销 来设置和切换任务。

你有多少个处理器?花费的时间取决于您正在执行的任务类型、您在任务中使用的资源类型等。 添加更多线程并不意味着您的进程会变快,它只是意味着如果有可用的空闲处理能力,那么 java 将尝试使用它们。

I have set the no. of threads to 4, but the time taken is same as that set to 2.

这是一个很常见的问题。我听过无数次,有时很难将单线程应用程序转换为多线程应用程序,但发现它并没有 运行 更快。由于线程开销和重构问题,它实际上可以 运行 变慢。

这个比喻是一个项目上过度劳累的研究员。你可以把他们的工作分开,让 4 名研究生同时工作,但如果他们都必须一直向研究人员提问,那么项目就不会进展得更快,而且 4 名研究生之间缺乏协调可以使项目花费更长的时间。

唯一向应用程序添加额外线程会明确提高吞吐量的情况是线程是:

  1. 完全独立——即在线程阻塞或必须同步内存时不在线程之间共享数据(或不共享数据)
  2. 完全CPU绑定——即仅进行数据处理,不等待磁盘或网络 IO 或其他系统资源
  3. 能够使用额外的系统CPUs

Here FirstRequest, SecondRequest, ThirdRequest and FourthRequest are different classes which calls another class which is common to all.

对,这是一个危险信号。 First/Second/... 请求 classes 可以并发工作,但如果它们必须调用公共 class 中的 synchronized 块,那么它们将相互阻塞。线程编程的棘手问题之一是如何在完成任务的同时限制数据共享。如果您展示更多常见的 class 那么我们也许可以为您提供更多帮助。

另一个大危险信号是任意数量的 IO。注意读写磁盘或网络。还要注意日志记录或其他输出。一个线程从磁盘读取,多个线程处理读取的内容,一个线程写入通常是高效的。但即便如此,如果处理不是很 CPU 密集,您可能看不到速度提升,因为应用程序的速度受磁盘设备的 IO 带宽限制。

为每个要处理的请求生成一个线程的 Web 应用程序效率很高,因为它们同时处理如此多的网络 IO 绑定请求。但真正的胜利是来自线程的代码改进能够专注于它的请求,然后当线程被阻塞等待网络或磁盘 IO 时,线程子系统将负责请求之间的上下文切换。