Concurrent Programming (II): Analysis of the thread pool

On the thread pool


description

Create a thread, start, destruction, etc. is a very resource-consuming process. Leads to the thread pool.

Thread pool action

  1. Reduce resource consumption, reuse already created threads.
  2. Improve response time, mission arrived already created directly by a thread, without waiting.
  3. Unified thread management, unified distribution of threads, monitoring and tuning (full-time person).

Create a thread pool

First, create

Currently there are six thread pool created. First to illustrate the four common way to create, in essence, it is to create a different thread by changing the parameters of the constructor. The constructor calls are final:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

The following are instructions for creating a demo to a thread pool:

1, create a cache thread
 ExecutorService threadPool = Executors.newCachedThreadPool();
 for(int i=0;i<10;i++){
     int temp = i;
     threadPool.execute(new Runnable() {
         @Override
         public void run() {
             System.out.println(Thread.currentThread().getName()+","+temp);
         }
     });
 }
 threadPool.shutdown();// 停掉线程池
2. Create a thread fixed length (common)
  ExecutorService threadPool = Executors.newFixedThreadPool(3);
  for (int i = 0; i < 10; i++) {
      int temp = i;
      threadPool.execute(new Runnable() {
          @Override
          public void run() {
              System.out.println(Thread.currentThread().getName()+","+temp);
          }
      });
  }
  threadPool.shutdown();// 停掉线程池
3. Create a regular thread
 ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(3);
 threadPool.schedule(new Runnable() {
     @Override
     public void run() {
         System.out.println("我是定时线程,三秒后启动");
     }
 },3, TimeUnit.SECONDS); // 第一个参数是任务,第二个参数是时间长度,第三个参数时间单位
 threadPool.shutdown();// 停掉线程池
4, create a single-threaded
 ExecutorService threadPool = Executors.newSingleThreadExecutor();
 for (int i = 0; i < 10; i++) {
     threadPool.execute(new Runnable() {
         @Override
         public void run() {
             System.out.println("我是单线程线程");
         }
     });
 }
 threadPool.shutdown();// 停掉线程池
Second, the thread pool Parameter Description

Key: Almost interview will be asked.

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {}

corePoolSize: a core number of threads

maximumPoolSize: maximum number of threads

keepAliveTimea: thread idle time

unit: TimeUnit enumeration type values ​​representative keepAliveTime unit of time, you can take the following values:

  • TimeUnit.DAYS; //天   
  • TimeUnit.HOURS; // hours   
  • TimeUnit.MINUTES; // minutes   
  • TimeUnit.SECONDS; // seconds   
  • TimeUnit.MILLISECONDS; // millisecond   
  • TimeUnit.MICROSECONDS; // subtle   
  • TimeUnit.NANOSECONDS; // ns

workQueue: blocking queue is used to store task waiting to be executed, determines the queue thread pool strategy, the following values:

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • SynchronousQueue

threadFactory: thread factory is used to create a thread

handler: thread deny policy. When a thread is created beyond maximumPoolSize, and the buffer queue is full, new tasks would refuse, the following values:

  • ThreadPoolExecutor.AbortPolicy: RejectedExecutionException discard task and throw an exception.
  • ThreadPoolExecutor.DiscardPolicy: the task is discarded, but does not throw an exception.   
  • ThreadPoolExecutor.DiscardOldestPolicy: discarding foremost task queue, and then try to re-execute task (repeat this procedure)   
  • ThreadPoolExecutor.CallerRunsPolicy: handle the task by the calling thread
Third, the process of creating a thread

The figure is the flow of execution thread pool:


Flow Description:

  1. Users submit jobs, first core thread pool, thread pool is to determine the core are full;

  2. How core thread pool is not full, the task execution thread; how the core thread is full, take the next step;

  3. Into the cache queue thread, it determines whether the buffer queue is full;

  4. If the thread buffer queue is full, enter the maximum thread pool;

  5. If the maximum thread pool is full, create threaded tasks;

  6. If the maximum thread pool is full, the rejected.

Create a second thread pool

5、newWorkStealingPool
ExecutorService m = Executors.newWorkStealingPool(2);

1) create a thread pool with a parallel level, parallel level determines the time up to the same number of threads in execution, if not pass parameters as a parallel level, the number of CPU will default to the current system.

2) Each thread maintains its own queue, the task execution is over, on their own initiative to get other tasks.

3) produced are daemon threads.

4) not ThreadPoolExecutor extension is an extension of ForkJoinPool.

5) Demo:

public class Main {
    public static void main(String[] args) throws Exception {
        // 设置并行级别为2,即默认每时每刻只有2个线程同时执行
        ExecutorService m = Executors.newWorkStealingPool(2);
        for (int i = 1; i <= 10; i++) {
            final int count=i;
            m.submit(new Runnable() {
                @Override
                public void run() {
                    Date now=new Date();
                    System.out.println("线程" + Thread.currentThread() + "完成任务:"+ count+"   时间为:"+    now.getSeconds());
                    try {
                        Thread.sleep(1000);//此任务耗时1s
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }); 
        }
        while(true){
            //主线程陷入死循环,来观察结果,否则是看不到结果的
        }
    }
}
6、ForkJoinPool

The idea is to thread pool, the use of recursive thinking, breaking large tasks into smaller tasks (can be split to control the particle size based on business requirements). Below a presentation face questions: a length 1,000,000 array elements is a random number less than one hundred, the various elements are added.

public class ForkJoin {
    static int[] nums = new int[1000000];
    static final int MAX_NUM = 50000;
    private static Random random = new Random();
    static {
        for (int i = 0; i < nums.length; i++) {
            nums[i] = random.nextInt(100);
        }
        System.out.println(Arrays.stream(nums).sum()); // 传统的方式计算
    }
    // 递归思想,不断将大任务分成小任务。
    // RecursiveAction 无返回值;RecursiveTask 有返回值。
    static class AddTask extends RecursiveAction{
        int start,end;
        AddTask(int start, int end) {
            this.start = start;
            this.end = end;
        }
        @Override
        protected void compute() {
            if(end-start<=MAX_NUM){
                long sum = 0L;
                for (int i = start; i < end; i++) {
                    sum += nums[i];
                }
                System.out.println("from+"+start+"to"+end+"="+sum);
            }else{
                int middle =start + (end-start)/2;
                AddTask addTask = new AddTask(start,middle);
                AddTask addTask2 = new AddTask(middle,end);
                addTask.fork();
                addTask2.fork();
            }
        }
    }
    public static void main(String[] args) throws IOException {
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        AddTask addTask = new AddTask(0,nums.length);
        forkJoinPool.execute(addTask);
        System.in.read();
    }
}

The advantage of this is that the thread pool, can take advantage of multi-cpu, the advantages of multi-core cpu, the task split into a plurality of "small tasks", a plurality of "small tasks" executed in parallel into a plurality of core processors; when several "small tasks" after the execution is complete, then merge the results of these can be.

Guess you like

Origin www.cnblogs.com/xzy-/p/10928978.html