Multi-Thread Process Slows Down System Response Time

This section provides a tutorial example showing why a multi-threaded process slows down the Windows response time. You should run threads with lower priorities to be nice to the system.

What will be the impact of Windows system performance, if we increase the number of running threads in MultithreadingCpuRunner.java to a very high number like 256? Let's try it out.

C:\>"\Program Files\java\jdk1.7.0_45\bin\java" 
   MultithreadingCpuRunner 1000 256

Thread parameter: 1000
Number of threads: 256
...
46 | 3 8 4 8 5 3 2 27 18 2 3 2 6 4 4 3 6 4 3 4 7 6 14  ...| 1846 | ...
51 | 4 3 3 3 3 4 3 29 16 4 4 4 3 3 4 4 3 4 2 4 3 4 14  ...| 1852 | ...
...

The total productivity is still at the same level. But my Windows system response time is very slow comparing to running MultithreadingCpuRunner.java with 4 threads. It takes a while to switch from one application to another.

My guess is that Windows system is designed to distributing CPU power at the thread level, not at the process level. Assuming that there are 100 processes on my Windows system. Out of the 100, there are only 10 processes are actively running with 1 thread in each process.

When running MultithreadingCpuRunner.java with 4 threads. The total actively running threads are 14, MultithreadingCpuRunner.java gets 4/14 = 28.57% chances to be served by the CPU. Other processes get 10/14 = 71.43% chances to be served by the CPU. Of course, 71.43% chance of getting served makes you feel the system is fast when you interact with one of the other processes.

When running MultithreadingCpuRunner.java with 256 threads. The total actively running threads are 266, MultithreadingCpuRunner.java gets 256/266 = 96.24% chances to be served by the CPU. Other processes get 10/14 = 3.76% chances to be served by the CPU. Of course, 3.76% chance of getting served makes you feel the system is slow when you interact with one of the other processes.

How to avoid this problem? When you are running a Java application server, which creates hundreds of threads because of high number of concurrent end users, you do want other Windows applications on the same machine to have a good response time.

The solution is to lower the execution priority on concurrently executing threads. Here is my revised version of thread runner program MultithreadingCpuRunner2.java which takes an extra argument to allow to set the thread execution priority:

/* MultithreadingCpuRunner2.java
 ^ With configurable thread priority between 1 and 10
 * Copyright (c) 2014, HerongYang.com, All Rights Reserved.
 */
public class MultithreadingCpuRunner2 {
   public static void main(String[] a) {

// Setting configuration
      long param = 1000; // Default parameter for the working thread
      int size = 1; // Default number of working threads
      int interval = 1; // Default monitoring interval in seconds
      int priority = Thread.NORM_PRIORITY; // Default priority
      if (a.length>0) param = Long.parseLong(a[0]);
      if (a.length>1) size = Integer.parseInt(a[1]);
      if (a.length>2) interval = Integer.parseInt(a[2]);
      if (a.length>3) priority = Integer.parseInt(a[3]);
      System.out.println("Thread parameter: "+param);
      System.out.println("Number of threads: "+size);
      System.out.println("Monitoring interval: "+interval);
      System.out.println("Thread priority: "+priority);

// Launching all threads
      PrimeCalculator[] threads = new PrimeCalculator[size];
      long[] counts = new long[size];
      for (int i=0; i<size; i++) {
          PrimeCalculator t = new PrimeCalculator(param);
          t.setPriority(priority);
          t.start();
          threads[i] = t;
          counts[i] = 0;
      }
      
// Monitoring overall productivity
      long startTime = System.currentTimeMillis();
      long lastTime = startTime;
      long grandTotal = 0;
      System.out.println(
         "Seconds | Productivity per thread | Total | Average");
      while (true) {
         try {
            Thread.sleep(interval*1000);
         } catch (InterruptedException e) {
            System.out.println("Monitor interrupted.");
         }
         long curTime = System.currentTimeMillis();
         long delta = (curTime - lastTime);
         long duration = (curTime - startTime);
         System.out.print(duration/1000+" | ");
         long total = 0;
         for (int i=0; i<size; i++) {
             long c = threads[i].jobCount;
             long d = c - counts[i];
             total += d;
             System.out.print((1000*d)/delta+" ");
             counts[i] = c;
         }
         grandTotal += total;
         System.out.println("| "+(1000*total)/delta
            +" | "+(1000*grandTotal)/duration);
         lastTime = curTime;
      }
   }
}

Now compile and test it with different priorities.

Test 1 - As we observed before, the system is very slow when running with the default priority level, 5:

C:\>"\Program Files\java\jdk1.7.0_45\bin\javac" 
   MultithreadingCpuRunner2.java

C:\>"\Program Files\java\jdk1.7.0_45\bin\java"
   MultithreadingCpuRunner2 1000 256 1

Thread parameter: 1000
Number of threads: 256
Monitoring interval: 1
Thread priority: 5
Seconds | Productivity per thread | Total | Average
...
8 | 21 6 3 3 6 3 6 20 6 3 6 3 30 3 9 3 6 3 6 3 3 3 6  ... | 1851 | ...
12 | 20 3 3 3 3 3 3 20 3 3 3 3 27 3 3 3 3 3 3 3 3 3 3 ... | 1855 | ...
16 | 20 3 6 6 3 6 3 20 3 3 3 6 27 6 3 3 3 3 3 6 6 3 3 ... | 1847 | ...
...

Test 2 - The system is extremely slow when running with the highest priority level, 10:

C:\>"\Program Files\java\jdk1.7.0_45\bin\java"
   MultithreadingCpuRunner2 1000 256 1 10
   
Thread parameter: 1000
Number of threads: 256
Monitoring interval: 1
Thread priority: 10
Seconds | Productivity per thread | Total | Average   
...
130 | 4 3 466 3 4 3 4 3 4 3 464 2 4 3 4 3 4 3 4 3 4 3 ... | 1772 | ...
135 | 0 0 0 0 0 0 0 0 0 0 14 0 0 13 0 14 0 14 0 14 0  ... | 1832 | ...
139 | 0 14 0 13 0 14 0 13 0 14 0 14 0 13 0 14 0 14 0  ... | 1824 | ...
... 

Test 3 - The system response time is normal when running with the lowest priority level, 1:

C:\>"\Program Files\java\jdk1.7.0_45\bin\java"
   MultithreadingCpuRunner2 1000 256 1 1

Thread parameter: 1000
Number of threads: 256
Monitoring interval: 1
Thread priority: 1
Seconds | Productivity per thread | Total | Average
...
14 | 465 0 0 14 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 464... | 1850 | ...
15 | 462 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 463 0... | 1837 | ...
16 | 456 0 0 0 0 0 0 14 0 14 0 14 0 14 0 14 0 14 0 14 ... | 1850 | ...
... 

Test 4 - The system response time is normal when running with the lowest priority level, 1, and 1024 threads:

C:\>"\Program Files\java\jdk1.7.0_45\bin\java"
   MultithreadingCpuRunner2 1000 1024 1 1

Thread parameter: 1000
Number of threads: 1024
Monitoring interval: 1
Thread priority: 1
Seconds | Productivity per thread | Total | Average
...
37 | 0 13 0 0 0 0 0 0 0 0 0 14 0 0 0 0 0 0 0 14 0 0 0 ... | 1828 | ...
38 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0... | 1833 | ...
39 | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0... | 1836 | ...
...

Here is what we learned from these tests:

Conclusion: When running a multi-threaded Java application, set thread priority to a lower level to be nice to the Windows system.

Last update: 2014.

Table of Contents

 About This Book

 Downloading and Installing JDK 1.8.0 on Windows

 Downloading and Installing JDK 1.7.0 on Windows

 java.lang.Runtime Class - The JVM Instance

 java.lang.System Class - The Operating System

 ClassLoader Class - Class Loaders

 Class Class - Class Reflections

 Sun's JVM - Java HotSpot VM

 JRockit JVM 28.2.7 by Oracle Corporation

 JVM Runtime Data Areas

 Memory Management and Garbage Collectors

 Garbage Collection Tests

 JVM Stack, Frame and Stack Overflow

 Thread Testing Program and Result

CPU Impact of Multi-Thread Applications

 PrimeCalculator.java - CPU Intensive Process

 CPU Intensive Process - 1 Thread per CPU

 Single Thread Process on 2-CPU-4-Thread Machine

 Two-Thread Process on 2-CPU-4-Thread Machine

 Multi-Thread Process on 2-CPU-4-Thread Machine

Multi-Thread Process Slows Down System Response Time

 Multi-Thread Process Running on JRockit JVM

 I/O Impact of Multi-Thread Applications

 CDS (Class Data Sharing)

 Micro Benchmark Runner and JVM Options

 Micro Benchmark Tests on "int" Operations

 Micro Benchmark Tests on "long" Operations

 Micro Benchmark Tests in JIT Compilation Mode

 Micro Benchmark Tests on "float" and "double" Operations

 Outdated Tutorials

 References

 PDF Printing Version