Four types of Java thread pool usage resolution

  • 2020-05-09 18:30:01
  • OfStack

This article analyzes four types of Java thread pool usage for your reference, as follows

1. Disadvantages of new Thread

Do you still perform an asynchronous task as new Thread?


new Thread(new Runnable() {

  @Override
  public void run() {
    // TODO Auto-generated method stub
    }
  }
).start();

Then you have too many out. The disadvantages of new Thread are as follows:

a. Poor performance every time new Thread creates a new object.
b. Threads lack unified 1 management, may create unlimited new threads, compete with each other, and may take up too much system resources resulting in a crash or oom.
c. Lack of more features, such as timed execution, periodic execution, thread interruption.

Compared to new Thread, Java provides four thread pools with the following benefits:

a. Reuse existing threads, reduce the overhead of object creation and death, good performance.
b. Can effectively control the maximum number of concurrent threads, improve the utilization of system resources, and avoid excessive resource competition and congestion.
c. Provides scheduled execution, scheduled execution, single thread, concurrency control and other functions.

2. Java thread pool

Java provides four thread pools through Executors, which are:

newCachedThreadPool creates a cacheable thread pool. If the thread pool length exceeds the processing requirement, the idle thread can be recovered flexibly. If there is no recovery, a new thread can be created.
newFixedThreadPool creates a fixed-length thread pool, which controls the maximum number of concurrent threads, and the excess threads will wait in the queue.
newScheduledThreadPool creates a fixed-length thread pool that supports timed and periodic task execution.
newSingleThreadExecutor creates a single-threaded thread pool that only executes tasks with 1-only worker threads, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority).
(1) newCachedThreadPool:

Create a cacheable thread pool, if the thread pool length exceeds the processing needs, can flexibly recycle the idle thread, if there is no recycling, then create a new thread. The sample code is as follows:


ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
    final int index = i;
  try {
    Thread.sleep(index * 1000);
  } 
    catch (InterruptedException e) {
      e.printStackTrace();
  }

cachedThreadPool.execute(new Runnable() {

@Override
public void run() {
  System.out.println(index);
}
});
}

The thread pool is infinite. When the second task is executed, the first task has been completed. The thread executing the first task will be reused instead of creating a new thread every time.

(2) newFixedThreadPool:

Create a fixed-length thread pool to control the maximum number of concurrent threads, which will wait in the queue. The sample code is as follows:


ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
  final int index = i;

  fixedThreadPool.execute(new Runnable() {

@Override
public void run() {
try {
  System.out.println(index);
  Thread.sleep(2000);
} catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
  }
}
});
}

Because the thread pool size is 3, each task outputs index after sleep for 2 seconds, so three Numbers are printed every two seconds.

The size of a fixed-length thread pool is best set based on system resources. Such as Runtime. getRuntime (.) availableProcessors (). See PreloadDataCache.

(3) newScheduledThreadPool:

Create a fixed - length thread pool, support timing and periodic task execution. The sample code for delayed execution is as follows:


ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
 scheduledThreadPool.schedule(new Runnable() {

@Override
public void run() {
  System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);

Represents a delay of 3 seconds.

Periodically execute the sample code as follows:


scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

@Override
public void run() {
  System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);

Represents one execution every three seconds after a delay of one second.

ScheduledExecutorService is more secure and powerful than Timer

(4) newSingleThreadExecutor:

Create a single-threaded thread pool that will only execute tasks with 1-only worker threads, ensuring that all tasks are executed in the specified order (FIFO, LIFO, priority). The sample code is as follows:


ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {

@Override
public void run() {
  try {
    System.out.println(index);
  Thread.sleep(2000);
} catch (InterruptedException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
    }
}
  });
}

The results are output in sequence, equivalent to the sequential execution of each task.

Most current GUI programs are single-threaded. Single thread in Android can be used for database operation, file operation, application batch installation, application batch deletion and other operations that are not suitable for concurrency but may block IO and affect the response of UI thread.

Function of thread pool:

The purpose of the thread pool is to limit the number of executing threads in the system.
Depending on the environment of the system, the number of threads can be set automatically or manually to achieve the best effect of running. Less waste system resources, more resulting in system congestion efficiency is not high. Thread pools are used to control the number of threads, while other threads queue up. When the first task is finished, the first task in the queue is taken and executed. If there is no waiting process in the queue, this 1 resource of the thread pool is waiting. When a new task needs to be run, if there are waiting worker threads in the thread pool, it can start running. Otherwise enter the wait queue.

Why use thread pools:

1. It reduces the number of threads created and destroyed, and each worker thread can be reused to perform multiple tasks.

2. The number of thread threads in the thread pool can be adjusted according to the system's capacity to avoid exhausting the server due to excessive memory consumption (each thread needs about 1MB memory, and the more open the thread, the more memory consumption will be, and finally crash).

The top-level interface for thread pools in Java is Executor, but Executor is not strictly a thread pool, but a tool for executing threads. The real thread pool interface is ExecutorService.

A few more important categories:

ExecutorService: real thread pool interface.

ScheduledExecutorService: can be similar to Timer/TimerTask to solve problems requiring repetitive tasks.

ThreadPoolExecutor: the default implementation of ExecutorService.

ScheduledThreadPoolExecutor: class implementation of periodic task scheduling that inherits ThreadPoolExecutor's ScheduledExecutorService interface implementation.

It is quite complicated to configure a thread pool, especially if the principle of thread pool is not very clear. It is likely that the configured thread pool is not optimal. Therefore, some static factories are provided in Executors class to generate some commonly used thread pools.

1.newSingleThreadExecutor

Create a single thread pool. This thread pool has only one thread working, which is equivalent to a single thread executing all tasks sequentially. If the one-only thread ends because of an exception, a new thread will replace it. This thread pool ensures that all tasks are executed in the order in which they were submitted.

2.newFixedThreadPool

Create a fixed-size thread pool. One thread is created each time a task is submitted until the thread reaches the maximum size of the thread pool. The size of the thread pool remains the same once it reaches its maximum size of 1, and if a thread ends because of an execution exception, the thread pool is replenished with a new thread.

3.newCachedThreadPool

Create a cacheable thread pool. If the thread pool size exceeds the number of threads needed to process the task,

Some of the idle threads (no tasks executed for 60 seconds) will be recycled, and as the number of tasks increases, this thread pool can intelligently add new threads to process the tasks. This thread pool does not impose a limit on the size of the thread pool, which is completely dependent on the maximum thread size that the operating system (or JVM) can create.

4.newScheduledThreadPool

Create a thread pool of infinite size. This thread pool supports the need to schedule and periodically execute tasks.

The sample code

1. Fixed size thread pool, newFixedThreadPool:


package app.executors; 

import java.util.concurrent.Executors; 
import java.util.concurrent.ExecutorService; 

/** 
 * Java Threads: thread pool  
 * 
 * @author xiho
 */ 
public class Test { 
  public static void main(String[] args) { 
    //  create 1 A pool of reusable threads with a fixed number of threads  
    ExecutorService pool = Executors.newFixedThreadPool(2); 
    //  Create a thread  
    Thread t1 = new MyThread(); 
    Thread t2 = new MyThread(); 
    Thread t3 = new MyThread(); 
    Thread t4 = new MyThread(); 
    Thread t5 = new MyThread(); 
    //  Put the thread into the pool for execution  
    pool.execute(t1); 
    pool.execute(t2); 
    pool.execute(t3); 
    pool.execute(t4); 
    pool.execute(t5); 
    //  Turn off the thread pool  
    pool.shutdown(); 
  } 
} 

class MyThread extends Thread { 
  @Override 
  public void run() { 
    System.out.println(Thread.currentThread().getName() + " Be executing... "); 
  } 
}

Output results:


pool-1-thread-1 Be executing...  
pool-1-thread-3 Be executing...  
pool-1-thread-4 Be executing...  
pool-1-thread-2 Be executing...  
pool-1-thread-5 Be executing... 

Change the parameters in ExecutorService pool = Executors.newFixedThreadPool (5) : ExecutorService pool = Executors.newFixedThreadPool (2), the output is:


pool-1-thread-1 Be executing...  
pool-1-thread-1 Be executing...  
pool-1-thread-2 Be executing...  
pool-1-thread-1 Be executing...  
pool-1-thread-2 Be executing... 

As you can see from the above results, the newFixedThreadPool parameter specifies the maximum number of threads that can be run, beyond which no threads will be run. Second, the threads that join the thread pool are in managed state, and the running of the threads is not affected by the joining order.

2. Single-task thread pool, newSingleThreadExecutor:

Simply change ExecutorService pool = Executors.newFixedThreadPool (2) to ExecutorService pool = Executors.newSingleThreadExecutor ();
Output results:


pool-1-thread-1 Be executing...  
pool-1-thread-1 Be executing...  
pool-1-thread-1 Be executing...  
pool-1-thread-1 Be executing...  
pool-1-thread-1 Be executing... 

As you can see, every time you call execute, you end up calling thread-1's run method.

3. Variable size thread pool, newCachedThreadPool:

ExecutorService = Executors.newCachedThreadPool (); ExecutorService = Executors.newCachedThreadPool ();

Output results:


ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
    final int index = i;
  try {
    Thread.sleep(index * 1000);
  } 
    catch (InterruptedException e) {
      e.printStackTrace();
  }

cachedThreadPool.execute(new Runnable() {

@Override
public void run() {
  System.out.println(index);
}
});
}

0

This approach has the advantage of creating a pool of new threads as needed, but reusing previously constructed threads when they are available.

4. Delayed connection pooling, newScheduledThreadPool:


ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
    final int index = i;
  try {
    Thread.sleep(index * 1000);
  } 
    catch (InterruptedException e) {
      e.printStackTrace();
  }

cachedThreadPool.execute(new Runnable() {

@Override
public void run() {
  System.out.println(index);
}
});
}

1

Output results:


ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
  for (int i = 0; i < 10; i++) {
    final int index = i;
  try {
    Thread.sleep(index * 1000);
  } 
    catch (InterruptedException e) {
      e.printStackTrace();
  }

cachedThreadPool.execute(new Runnable() {

@Override
public void run() {
  System.out.println(index);
}
});
}

2

The above is the entire content of this article, I hope to help you with your study.


Related articles: