Home>

Starting with java 5, java provides its own thread pool.A thread pool is a container for threads.Only a specified number of threads are executed at a time. java.util.concurrent.threadpoolexecutor is one such thread pool.It's flexible,But it is also more complicated to use,This article introduces it.

The first is the constructor.Take the simplest constructor as an example:

public threadpoolexecutor (
      int corepoolsize,      int maximumpoolsize,      long keepalivetime,      timeunit unit,      blockingqueue<runnable>workqueue)

It looks complicated.Here to introduce.

corepoolsize refers to the reserved thread pool size.

The maximumpoolsize refers to the maximum size of the thread pool.

Keepalivetime refers to the timeout period for idle threads to end.

unit is an enum,A unit representing keepalivetime.

workqueue represents the queue holding tasks.

We can understand the meaning of these parameters from the work of the thread pool.The thread pool works as follows:

1. When the thread pool was just created,There is no thread in it.The task queue is passed in as a parameter.However, even if there are tasks in the queue,The thread pool does not execute them immediately.

2. When calling the execute () method to add a task,The thread pool will make the following judgments:

a. If the number of running threads is less than corepoolsize, then immediately create a thread to run this task;

b. If the number of running threads is greater than or equal to corepoolsize, put this task in a queue.

c. If the queue is full at this time,And the number of running threads is less than the maximumpoolsize, then you still need to create threads to run this task

d. If the queue is full,And the number of running threads is greater than or equal to the maximumpoolsize, the thread pool will throw an exception,Tell the caller "I can no longer accept the task."

3. When a thread completes a task,It will take the next task from the queue for execution.

4. When a thread has nothing to do,When a certain time (keepalivetime) is exceeded, the thread pool will judge,If the number of threads currently running is greater than corepoolsize, the thread is stopped.So after all tasks of the thread pool are completed,It will eventually shrink to the size of corepoolsize.

This process illustrates,It is not necessary to join the task first, and it will always be executed first.Assuming the queue size is 10, corepoolsize is 3, and maximumpoolsize is 6, then when 20 tasks are added,The order of execution is this:tasks 1, 2, 3 are executed first, and then tasks 4-13 are put into a queue.At this time the queue is full,Tasks 14, 15, 16 will be executed immediately,Tasks 17-20 will throw exceptions.The final order is:1, 2, 3, 14, 15, 16, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13. The following is an example of thread pool usage:

public static void main (string [] args) {
  blockingqueue<runnable>queue=new linkedblockingqueue<runnable>();
  threadpoolexecutor executor=new threadpoolexecutor (3, 6, 1, timeunit.days, queue);
  for (int i=0;i<20;i ++) {
    executor.execute (new runnable () {
      public void run () {
        try {
          thread.sleep (1000);
        } catch (interruptedexception e) {
          e.printstacktrace ();
        }
        system.out.println (string.format ("thread%d finished", this.hashcode ()));
      }
    });
  }
  executor.shutdown ();
}

The description of this example is as follows:

1, blockingqueue is just an interface,Common implementation classes are linkedblockingqueue and arrayblockingqueue. The advantage of using linkedblockingqueue is that there are no size restrictions.In this case,Because the queue is not full,So execute () does not throw an exception,And the number of threads running in the thread pool will never exceed corepoolsize, and the keepalivetime parameter is meaningless.

2. The shutdown () method does not block.After calling the shutdown () method,The main thread ends immediately,The thread pool will continue to run until all tasks have completed execution.If you do not call the shutdown () method, the thread pool will be maintained forever,So you can add new tasks at any time.

I have only introduced a small part of this thread pool here.threadpoolexecutor is highly scalable,But the premise of extending it is to be familiar with how it works.A later article will show how to extend the threadpoolexecutor class.

The ava.util.concurrent.threadpoolexecutor class provides rich extensibility.You can customize its behavior by creating subclasses of it.For example, I want to print a message after each task ends,But I can't modify the task object,Then I can write this:

threadpoolexecutor executor=new threadpoolexecutor (size, maxsize, 1, timeunit.days, queue) {
  @override
  protected void afterexecute (runnable r, throwable t) {
    system.out.println ("task finished.");
  }
};

In addition to the afterexecute method,The threadpoolexecutor class also has beforeexecute () and terminated () methods that can be overridden,They are executed before the task is executed and after the entire thread pool is stopped.

In addition to adding actions before and after the task, threadpoolexecutor also allows you to customize the execution strategy when adding tasks fails.You can call the thread pool's setrejectedexecutionhandler () method to replace the existing strategy with a custom rejectedexecutionhandler object. threadpoolexecutor provides 4 existing strategies,They are:

threadpoolexecutor.abortpolicy:Rejects the task and throws an exception

threadpoolexecutor.discardpolicy:Rejects the task but does nothing

threadpoolexecutor.callerrunspolicy:indicates that the task is rejected,And execute the task directly in the caller's thread

threadpoolexecutor.discardoldestpolicy:indicates that the first task in the task queue is dropped first,Then add this task to the queue.

Here is an example:

threadpoolexecutor executor=new threadpoolexecutor (size, maxsize, 1, timeunit.days, queue);

executor.setrejectedexecutionhandler (new threadpoolexecutor.discardpolicy ());

In addition,You can also write your own strategy by implementing the rejectedexecutionhandler interface.Below is an example:

threadpoolexecutor executor=new threadpoolexecutor (3, 6, 1, timeunit.seconds, queue,    new rejectedexecutionhandler () {
      public void rejectedexecution (runnable r, threadpoolexecutor executor) {
        system.out.println (string.format ("task%d rejected.", r.hashcode ()));
      }
    }
);
  • Previous Nine application scenarios of this in JavaScript and three composite application scenarios
  • Next Pure js code implements elements of unknown width and height to be displayed vertically and horizontally in the specified elemen