Java Concurrent Programming Ten Thread Pool Tool Class

Posted by AIS4U on Tue, 06 Aug 2019 10:41:04 +0200

Thread pool


Java Concurrent Programming 1: Concurrent Basis Knows
Java Concurrent Programming II: Threads in Java
Java concurrent programming three: volatile use
Java concurrent programming four: synchronized and lock
Java Concurrent Programming V: Atomic Atomic Classes
Java concurrent programming 6: concurrent queues
Java Concurrent Programming 7: ReentrantReadWriteLock and StampedLock
Java concurrent programming 8: CountDownLatch, Cyclic Barrier, Semaphore and Exchanger
Java Concurrent Programming 9: Thread Pool
Executors in Jdk provides us with seven common thread pool tool classes, which are:

  1. New Fixed ThreadPool: Create a fixed number of reusable thread pools.
  2. New Cached ThreadPool: Create a cacheable thread pool that allows flexible thread recovery.
  3. New Scheduled ThreadPool: Create a timed thread pool to support periodic task execution.
  4. New Single ThreadExecutor: Create a single threaded thread pool, the only worker thread to perform tasks, tasks in the established order (FIFO, LIFO, priority) to execute.
  5. New Single Thread Scheduled Executor:: Create a single threaded timed thread pool to perform tasks periodically or delayed.
  6. New Work Stealing Pool: The thread pool for parallel level work stealing mode defaults to the number of CPU s in size. (1.8)
  7. ForkJoinPool: A thread pool that supports the decomposition of large tasks into small tasks, usually used in conjunction with RecursiveAction or RecursiveTask, a subclass of the ForkJoinTask interface. (1.8)

newFixedThreadPool

If the core thread is not full, the thread is created to execute, and if it is not satisfied, it is placed in the queue.

public class Test {
    public static void main(String[] args) {
        ExecutorService executorService= Executors.newFixedThreadPool(5);
       for (int i = 1; i <11 ; i++) {
            int count = i;
            executorService.execute(()->{
               System.out.println(Thread.currentThread().getName()+"Executed the task"+ count);
            });
        }
         executorService.shutdown();
    }
}

Operation results:

pool-1-thread-1 performs task 1
pool-1-thread-5 performs task 5
pool-1-thread-4 performs task 4
pool-1-thread-3 performs task 3
pool-1-thread-2 performs task 2
pool-1-thread-1 performs task 6
pool-1-thread-4 performs task 8
pool-1-thread-2 performs task 9
pool-1-thread-5 performs task 7
pool-1-thread-3 performs task 10

newCachedThreadPool

Submitted tasks are created if there are no idle threads. If there are multiple idle threads, the spatial threads are reclaimed by default for 60 seconds.

public class Test {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 1; i <11 ; i++) {
            int count = i;
            //Thread.sleep(100*count);
            executorService.execute(()->{
               System.out.println(Thread.currentThread().getName()+"Executed the task"+ count);
            });
        }   
        executorService.shutdown();
    }
}

Operation results:

pool-1-thread-1 performs task 1
pool-1-thread-4 performs task 4
pool-1-thread-2 performs task 2
pool-1-thread-3 performs task 3
pool-1-thread-5 performs task 5
pool-1-thread-6 performs task 6
pool-1-thread-7 performs task 7
pool-1-thread-8 performs task 8
pool-1-thread-9 performs task 9
pool-1-thread-10 performs task 10

Unscramble Thread.sleep(100*count) execution results are as follows:

pool-1-thread-1 performs task 1
pool-1-thread-1 performs task 2
pool-1-thread-1 performs task 3
pool-1-thread-1 performs task 4
pool-1-thread-1 performs task 5
pool-1-thread-1 performs task 6
pool-1-thread-1 performs task 7
pool-1-thread-1 performs task 8
pool-1-thread-1 performs task 9
pool-1-thread-1 performs task 10

newScheduledThreadPool

There are three ways to perform tasks periodically.

  1. How long does schedule take to execute a task, only once?
  2. How long does scheduleAtFixedRate take to execute the task, and then it is executed periodically.
  3. SchduleWithFixedDelay is similar to scheduleAtFixedRate in that the former is executed at intervals after the task is executed, whereas the latter is executed at the point of arrival regardless of whether the execution is completed or not.
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
        System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").format(LocalDateTime.now())+": newScheduledThreadPool start....");
        executorService.schedule(()->{
            System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").format(LocalDateTime.now())+": schedule 3 Run in seconds");
        },3, TimeUnit.SECONDS);
        executorService.scheduleAtFixedRate(()->{
            try {
                System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").format(LocalDateTime.now())+": scheduleAtFixedRate 5 Run 2 seconds later and run once");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },5,2,TimeUnit.SECONDS);
        executorService.scheduleWithFixedDelay(()->{
            try {
                System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").format(LocalDateTime.now())+": scheduleAtFixedRate 10 Run 2 seconds later and run once");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },5,2,TimeUnit.SECONDS);

Operation results:

2019-06-2602:26:57: New Scheduled ThreadPool begins...
2019-06-2602:27:00:schedule runs after 3 seconds
2019-06-2602:27:02:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:02:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:07:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:09:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:12:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:16:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:17:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:22:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:23:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:27:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:30:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:32:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:37:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:37:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:42:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:44:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:47:scheduleAtFixed Rate runs once in 2 seconds after 5 seconds
2019-06-2602:27:51:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:27:52:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:57:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:27:58:scheduleAtFixedRate runs once in 2 seconds after 10 seconds
2019-06-2602:28:02:scheduleAtFixedRate runs once in 2 seconds after 5 seconds
2019-06-2602:28:05:scheduleAtFixedRate runs once in 2 seconds after 10 seconds

newWorkStealingPool

A thread pool with enough threads is created to maintain the corresponding parallel level. It is a work stealing mode. Each processor's core corresponds to the task to be processed. When a core's task is processed, it helps other cores to process the task.

        // The default is the system's number of cores
        ExecutorService executorService = Executors.newWorkStealingPool(4);
        for (int i = 0; i < 10; i++) {
            int count = i;
            executorService.execute(()->{
                try {
                    Thread.sleep(count *100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            });
        }
        // Work Stealing Pool is a background thread, otherwise you can't see the results.
          System.in.read();

Operation results:

ForkJoinPool-1-worker-1
ForkJoinPool-1-worker-2
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-1
ForkJoinPool-1-worker-0
ForkJoinPool-1-worker-2
ForkJoinPool-1-worker-3
ForkJoinPool-1-worker-1
ForkJoinPool-1-worker-0
ForkJoinPool-1-worker-2

As can be seen from the results, when thread 1 finishes executing, it will help to perform other tasks again.

ForkJoinPool

In concurrent programming, we often encounter dividing large tasks into small tasks to perform. Fork Join Pool is a thread pool supporting task decomposition, which splits tasks according to pre-set rules, and finally merges them. Generally, ForkJoinTask is used in conjunction with the task assignment interface ForkJoinTask. ForkJoinTask has two implementation classes: RecursiveAction and RecursiveTask. The difference is that the former has no return value and the latter has a return value.

 // Maximum task load
    private static final int MAX_NUMBER = 1000000;
    private static int[] nums = new int[5000000];
    static {
        for (int i = 0; i < nums.length; i++) {
            nums[i] = new Random().nextInt(100)+1;
        }
    }
    public static void main(String[] args) throws InterruptedException,ExecutionException {
        System.out.println("The results are as follows:"+ Arrays.stream(nums).sum());
        // The default is the system's number of cores
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        MyTask myTask = new MyTask(0, nums.length);
        forkJoinPool.submit(myTask);
        System.out.println("The results are as follows:"+myTask.get());
    }
    static class MyTask extends RecursiveTask<Long>{

        private int start;
        private int end;

        public MyTask(int start, int end){
               this.start = start;
               this.end = end;
        }

        @Override
        protected Long compute() {
            if (end - start < MAX_NUMBER){
                // No more assignments
                long result = 0;
                for (int i = start; i < end; i++) {
                    result = result + nums[i];
                }
                System.out.println("from: "+start+"---to: "+end+"----="+result);
                return result;
            }else {
                // Continue task segmentation
                int middle = start + (end - start)/2 ;
                MyTask leftTask = new MyTask(start, middle);
                MyTask rightTask = new MyTask(middle, end);
                // Execution of tasks
                leftTask.fork();
                rightTask.fork();
                return leftTask.join()+rightTask.join();
            }
        }
    }

Operation results:

The results were: 252400222
from: 2500000—to: 3125000----=31505184
from: 1875000—to: 2500000----=31552670
from: 3125000—to: 3750000----=31623470
from: 0—to: 625000----=31505421
from: 3750000—to: 4375000----=31531536
from: 1250000—to: 1875000----=31554030
from: 625000—to: 1250000----=31544988
from: 4375000—to: 5000000----=31582923
//The results were: 252400222

Note: ForkJoinPool creates a large number of subtasks during its execution, leading to GC garbage collection.

Instructions


Ali's explanation is authoritative enough. Make a thread pool by yourself.

 ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 60, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5), new MyThreadFactory(), (r, executor1) -> System.out.println( executor1.toString()));
        for (int i = 0; i < 10; i++) {
            executor.execute(()->{
                try {
                    Thread.sleep((new Random().nextInt(100)+1)*100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread()+"Executed");
                System.out.println( executor.toString());
            });
        }
    }
     static class MyThreadFactory implements ThreadFactory {
       private final AtomicInteger mThreadNumber = new AtomicInteger(0);
        @Override
        public Thread newThread(Runnable r) {
            return new Thread(r,"my-thread-" + mThreadNumber.incrementAndGet());
        }
    }

Operation results:

java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 5, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 5, completed tasks = 0]
Thread[my-thread-3,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 5, completed tasks = 0]
Thread[my-thread-3,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 4, completed tasks = 1]
Thread[my-thread-3,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 3, completed tasks = 2]
Thread[my-thread-2,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 2, completed tasks = 3]
Thread[my-thread-1,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 1, completed tasks = 4]
Thread[my-thread-2,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 5]
Thread[my-thread-3,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 2, queued tasks = 0, completed tasks = 6]
Thread[my-thread-1,5,main]Executed
java.util.concurrent.ThreadPoolExecutor@50040f0c[Running, pool size = 3, active threads = 1, queued tasks = 0, completed tasks = 7]

For parameters and results, see the previous chapter.

Topics: Java Programming JDK