First, the following problems exist

new Thread() {
    @Override
    public void run() {// business logic}}.start();Copy the code

  • First, creating and destroying objects frequently is a performance cost.
  • If a large number of users occupy too many resources, our service may break down due to insufficient resources.
  • To sum up, in actual development, this operation is actually not an option.

What are the advantages of using thread pools

  • Thread pool usage increases, reducing object creation and destruction.
  • Thread pool can control the number of threads, effectively promote the use of server resources, to avoid the problem of downtime due to insufficient resources;

Four ways to use thread pools

1, newCachedThreadPool

  • Create a thread pool that effectively reclaims threads if there are too many threads in the pool, or creates new threads if there are not enough.
public static void method() throws Exception {

    ExecutorService executor = Executors.newCachedThreadPool();

    for (int i = 0; i < 5; i++) {

        final int index = i;

        Thread.sleep(1000);

        executor.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + ""+ index); }}); }}Copy the code

The execution result

Through analysis, I can see that the entire execution is performed by a single thread, which realizes the reuse of threads and does not create redundant threads.

What happens when our business takes a certain amount of time to process. So let’s do a simulation.

As you can see, you now need several threads to execute alternately.

  • Disadvantages: Although this method can automatically expand the number of threads to process our business according to the business scenario, we cannot control how many threads are needed at most to process the shortage at the same time.
  • Advantage: If the second task starts and the first task is finished, the second task will reuse the thread created by the first task instead of re-creating a new thread, which improves the reuse rate of threads.

2, newFixedThreadPool

This way you can specify the number of threads in the thread pool. For example, if the maximum size of a bath room is 20 people at a time, those who come from behind will have to wait in line outside. If you push hard, there will only be one situation, friction…

First, we will test if the maximum capacity is one thread, which is what we predicted.

public static void method_01() throws InterruptedException {

    ExecutorService executor = Executors.newFixedThreadPool(1);

    for (int i = 0; i < 10; i++) {

        Thread.sleep(1000);
        final int index = i;

        executor.execute(() -> {
            try {
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "" + index);
        });
    }
    executor.shutdown();
}
Copy the code

The execution result

Let’s change it to 3 threads and see what happens

Advantages: The two results show that the number of threads in newFixedThreadPool can be controlled, so we can control the maximum number of threads to maximize the utilization of our server, and ensure that the sudden increase in traffic will not take up too much server resources.

3, newScheduledThreadPool

The thread pool supports timing and periodic task execution. We can delay the execution time of the task or set a periodic time for the task to be repeated. There are two ways to delay in this thread pool.

  • scheduleAtFixedRate

Testing a

public static void method_02() {
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);

    executor.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            long start = new Date().getTime();
            System.out.println("ScheduleAtFixedRate Start time :" +
                    DateFormat.getTimeInstance().format(new Date()));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long end = new Date().getTime();
            System.out.println("ScheduleAtFixedRate Takes time to execute =" + (end - start) / 1000 + "m");
            System.out.println("ScheduleAtFixedRate Execution time:" + DateFormat.getTimeInstance().format(new Date()));
            System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
        }
    }, 1, 5, TimeUnit.SECONDS);
}
Copy the code

The execution result

Test two

Conclusion: The difference between the two methods is the execution time of the task. If the interval is longer than the execution time of the task, the task is not affected by the execution time. If the interval is less than the execution time of the task, then the task will be executed immediately after the completion of execution, so the interval will be disrupted.

  • scheduleWithFixedDelay

Testing a

public static void method_03() {
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    executor.scheduleWithFixedDelay(new Runnable() {
        @Override
        public void run() {
            long start = new Date().getTime();
            System.out.println("ScheduleWithFixedDelay Start time :" +
                    DateFormat.getTimeInstance().format(new Date()));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long end = new Date().getTime();
            System.out.println("ScheduleWithFixedDelay Takes time to execute =" + (end - start) / 1000 + "m");
            System.out.println("ScheduleWithFixedDelay:"
                    + DateFormat.getTimeInstance().format(new Date()));
            System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
        }
    }, 1, 2, TimeUnit.SECONDS);
}
Copy the code

The execution result

Test two

public static void method_03() {
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

    executor.scheduleWithFixedDelay(new Runnable() {
        @Override
        public void run() {
            long start = new Date().getTime();
            System.out.println("ScheduleWithFixedDelay Start time :" +
                    DateFormat.getTimeInstance().format(new Date()));
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long end = new Date().getTime();
            System.out.println("ScheduleWithFixedDelay Takes time to execute =" + (end - start) / 1000 + "m");
            System.out.println("ScheduleWithFixedDelay:"
                    + DateFormat.getTimeInstance().format(new Date()));
            System.out.println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
        }
    }, 1, 2, TimeUnit.SECONDS);
}
Copy the code

The execution result

The scheduleWithFixedDelay interval is not affected by the time the task is executed.

4, newSingleThreadExecutor

This is a single-thread pool that is executed by a single thread all the time.

public static void method_04() {

    ExecutorService executor = Executors.newSingleThreadExecutor();

    for (int i = 0; i < 5; i++) {
        final int index = i;
        executor.execute(() -> {
            try {
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "" + index);
        });
    }
    executor.shutdown();
}
Copy the code

The execution result

Function of thread pool

Thread pools are used to improve system performance and utilization. As mentioned at the beginning of this article, if we use the simplest way to create threads, if the number of users is large, there will be a lot of creation and destruction of threads, which may result in the server consuming more performance on creating and destroying threads than on the actual business. Thread pools are designed to solve these problems.

There are many other designs with the same idea, such as database connection pools. Due to frequent connections to databases, however, creating connections is a performance cost, and all database connection pools arise.