Thread Pool

  • 1.jdk multitasking execution framework
  • 2. Detailed explanation and use of Concurrent.util tool class
  • 3. (Reentrant locks, read-write locks) Advanced locks

Thread Pool (Executor Framework 4/25/2018 10:39:45 PM )

In order to better control multi-threading, jdk provides a set of thread framework Executor to help developers effectively control threads. They are all in the java.util.concurrent package, which is the core of jdk concurrent package, one of which is The class to be compared: Executors, which plays the role of a thread factory, we use Executors to create a thread pool method:

newFixedThreadPool()方法,该方法返回一个固定数量的线程池,该方法的线程数量始终不变,当有一个任务提交时,若线程池中空闲,则立即执行,若没有,则会
暂缓在一个任务队列中等待空闲的的线程去执行.
构造方法:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

newSingleThreadExecutor()方法,创建一个线程的线程池,若线程空闲则执行,若没有空闲线程则暂缓在任务队列中
构造方法:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

newCachedThreadPool()方法,返回一个可以根据实际情况调整线程个数的线程池,不限制最大线程数量,若有空闲的线程则执行任务,若无任务,则不创建爱线程,
并且每一个空闲线程会在60秒后自动回收
构造方法:

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,   //60秒之内没有任务过来  就把线程回收
                                  new SynchronousQueue<Runnable>());  //这个是一个没有任何容量的队列(直接take()拿)
}

newScheduledThreadPool()方法,该方法返回一个SchedeExecutoeServcice()对象,但该线程池也可以指定线程的数量
这里面的没有个线程都可以实现定时的功能   ---(可以规定时间移除)
构造方法:

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);  //返回的是这个类
}

ScheduledThreadPoolExecutor:

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());      //带有延迟时间的队列
}

These four static methods, the bottom layer are all implemented through ThreadPoolExecutor.

Custom thread pool:

If the Executors factory class cannot meet our needs, you can create a custom thread pool yourself. In fact, the internal implementation of the thread creation method in the Executors factory class uses the ThreadPoolExecutors class, which can customize threads. The construction method is as follows :

    public ThreadPoolExecutor(int corePoolSize,   //核心线程数
                              int maximumPoolSize,  //最大的线程数
                              long keepAliveTime,  //线程池里面的线程保持活着的时间(空闲时间)
                              TimeUnit unit,    //指定时间单位
                              BlockingQueue<Runnable> workQueue)   //在等着的线程放在这个队列里面
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler  //把这个线程拒绝掉(不执行这个任务)
    }

corePoolSize: The number of threads that exist once the thread pool is created.


newScheduledThreadPool : can implement timing operations:

example:

class Temp extends Thread {
    @Override
    public void run() {
        System.out.println("run....");
    }
}
public class ScheduledThreadPool {
    public static void main(String[] args) {
        Temp command = new Temp();
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        ScheduledFuture<?> scheduleTask = scheduler.scheduleWithFixedDelay(command, 1, 2, TimeUnit.SECONDS);

    }

Analysis: The initialization delay time is 1 second, and then the task is not executed every 2 seconds. It is similar to the Timer class in java

Custom thread pool usage details:

This constructor is critical to what type of queue is

在使用有界队列的时候,
若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,若大于corePoolSize,则会将任务加入队列,若队列
已满,则在线程数不大于maximumPoolSize的前提下,创建新的线程,若线程数大于maximumPoolSize,则执行拒绝策略.或其他自定义方式.
无界的任务队列时:
LinkedBlockingQueue.与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况.当有新任务到来,系统的线程数,
小于corePoolSize,则新建线程执行任务.当达到corePoolSize后,就不会继续增加.若后续仍有新的任务加入,而没有空闲的线程资源,则任务直接进入队列等待.
若任务创建和处理的速度差异很大,无界队列会保持快速增长,知道耗尽系统内存.

jdk的拒绝策略:
AbortPolicy:直接抛出异常组织系统正常工作
CallerRunPolicy:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务.
DiscardOldestPolicy:丢一一个老的请求,尝试再次提交当前任务.
DiscardPolicy:丢弃无法处理的任务,不急于任何处理.

The rejection strategy provided by jdk is not particularly good, it is best to customize the rejection strategy, if you need to implement a custom rejection strategy, you can implement the RejectedExecutionHandler interface

Use a bounded queue: (ArrayBlockingQueue)

public class MyTask implements Runnable {

        private int taskId;
        private String taskName;

        public MyTask(int taskId, String taskName) {
            super();
            this.taskId = taskId;
            this.taskName = taskName;
        }
        public int getTaskId() {
            return taskId;
        }
        public void setTaskId(int taskId) {
            this.taskId = taskId;
        }
        public String getTaskName() {
            return taskName;
        }
        public void setTaskName(String taskName) {
            this.taskName = taskName;
        }
        @Override
        public void run() {
            try {
                System.out.println("run taskId = " + this.taskId);
                Thread.sleep(5*1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public String toString() {
            return Integer.toString(this.taskId);
        }
    }

public class UseThreadPoolExecutor1 {
    public static void main(String[] args) {
        /**
         * 在使用有界队列时,若有新的任务需要执行,如果线程池实际线程数小于corePoolSize,则优先创建线程,
         * 若大于corePoolSize,则会将任务加入队列, 若队列已满,则在总线程数不大于maximumPoolSize的前提下,创建新的线程,
         * 若线程数大于maximumPoolSize,则执行拒绝策略。或其他自定义方式。
         * 
         */
         ThreadPoolExecutor pool = new ThreadPoolExecutor(1,  //corePoolSize 
                 2,  //  maximumPoolSize 
                 60, //  keepAliveTime
                 TimeUnit.SECONDS, 
                 new ArrayBlockingQueue<Runnable>(3));   //指定一种队列(有界队列)


        MyTask mt1 = new MyTask(1, "任务1");
        MyTask mt2 = new MyTask(2, "任务2");
        MyTask mt3 = new MyTask(3, "任务3");
        MyTask mt4 = new MyTask(4, "任务4");
        MyTask mt5 = new MyTask(5, "任务5");
        MyTask mt6 = new MyTask(6, "任务6");

        pool.execute(mt1);
        pool.execute(mt2);
        pool.execute(mt3);
        pool.execute(mt4);
        pool.execute(mt5);
        pool.execute(mt6);

        pool.shutdown();
    }
}

Analysis: The number of core threads in this custom thread pool is 1, the number of threads that can be placed in a bounded queue is 3, and the maximum number of threads is 2.

所以当有四个以内的线程任务时,都是一次执行一个线程,当有5个线程任务是,队列3个满了,所以得重新创建一个新的线程用来执行第5个个任务,那么现在就是一次
可以执行两个线程了, 1,5第一次执行,2,3第二次执行,4第三次执行.
但是如果创建6个线程的话,那么就会满了,最大线程个数达到了两个,队列能缓存的线程个数是3个,也满了,这是第六个线程任务就会被拒绝,抛出异常.

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task 6 rejected from java.util.concurrent.ThreadPoolExecutor@70dea4e[Running, pool size = 2, active threads = 2, queued tasks = 3, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.threadbasic023.UseThreadPoolExecutor1.main(UseThreadPoolExecutor1.java:34)
run taskId = 1
run taskId = 5
run taskId = 2
run taskId = 3
run taskId = 4

Use unbounded queue: (LinkedBlockingQueue)
public class UseThreadPoolExecutor2 implements Runnable {

        private static AtomicInteger count = new AtomicInteger(0);
        @Override
        public void run() {
            try {
                int temp = count.incrementAndGet();
                System.out.println("任务" + temp);
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        public static void main(String[] args) {
            BlockingQueue queue = new LinkedBlockingQueue<Runnable>();

            ExecutorService executor = new ThreadPoolExecutor(5, 10, 120L, TimeUnit.SECONDS, queue);
            for(int i = 0; i < 20; i++) {
                executor.execute(new UseThreadPoolExecutor2());
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("queue size:" + queue.size());

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

The length of this unbounded queue is 15. Note that at most 5 thread tasks can be executed at a time. (After reaching corePoolSize, no new threads will be added. MaximumPoolSize is meaningless)

任务1
任务2
任务3
任务4
任务5
queue size:15
任务6
任务7
任务8
任务9
任务10
任务11
任务12
任务13
任务14
任务15
任务16
任务17
任务18
任务19
任务20

If you switch to a bounded queue this time:

public class UseThreadPoolExecutor2 implements Runnable {

private static AtomicInteger count = new AtomicInteger(0);
    @Override
    public void run() {
        try {
            int temp = count.incrementAndGet();
            System.out.println("任务" + temp);
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}
public static void main(String[] args) {
//      BlockingQueue queue = new LinkedBlockingQueue<Runnable>();
    BlockingQueue queue = new ArrayBlockingQueue<Runnable>(10);

    ExecutorService executor = new ThreadPoolExecutor(5, 8, 120L, TimeUnit.SECONDS, queue);
    for(int i = 0; i < 20; i++) {
        executor.execute(new UseThreadPoolExecutor2());
    }
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("queue size:" + queue.size());

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
  }
}

This time, 8 thread tasks are executed, and 10 thread tasks can be placed in the queue, so a total of 18 thread tasks are executed, and two thread tasks are rejected.

打印结果:
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.threadbasic023.UseThreadPoolExecutor2@75b84c92 rejected from java.util.concurrent.ThreadPoolExecutor@6bc7c054[Running, pool size = 8, active threads = 8, queued tasks = 10, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at com.threadbasic023.UseThreadPoolExecutor2.main(UseThreadPoolExecutor2.java:30)
任务1
任务2
任务3
任务4
任务5
任务6
任务7
任务8
任务9
任务10
任务12
任务11
任务14
任务13
任务15
任务16
任务17
任务18

The rejection policy that comes with jdk is not particularly easy to use: you can customize the rejection policy

public class MyRejected implements RejectedExecutionHandler {

    public MyRejected() {

    }

    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("自定义处理...");
        System.out.println("当前被拒绝的任务为:" + r.toString());
    }
}

Some task processing can also be customized in the custom strategy: when the strategy is rejected, the log is generally only recorded, and when it is not a peak period, the log is parsed and reprocessed

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325782666&siteId=291194637