线程池的学习(二)

四种常见的线程池,本章节来讲讲这四种线程池:

  • CachedThreadPool:可缓存的线程池
  • SecudleThreadPool:周期性执行任务的线程池
  • SingleThreadPool:单线程线程池
  • FixedThreadPool:定长的线程池

(1). newCachedThreadPool

  1. 创建一个可缓存线程池;
  2. 如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  3. 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
  4. CachedThreadPool适用于处理大量、耗时少的任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CachedThreadDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+",i:" + temp);
                }
            });
        }
    }
}

运行结果如下:

 执行方法图片来源:https://blog.csdn.net/qq_36299025/article/details/89490858

(2). SecudleThreadPool

  1. 创建一个周期线程池,支持定时及周期性任务执行。

延迟执行3秒执行:

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadDemo {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            scheduledExecutorService.schedule(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+",i:" + temp);
                }
            },3, TimeUnit.SECONDS);//表示延迟3秒执行
        }
    }
}

定时任务,延迟1秒后每10秒执行一次。

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledThreadDemo {
    public static volatile int no=0;
    public static void main(String[] args) {
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            scheduledExecutorService.scheduleAtFixedRate(new Runnable() {//表示延迟1秒后每10秒执行一次。
                @Override
                public void run() {
                    ++no;
                    System.out.println(Thread.currentThread().getName()+",i:" + temp+"第"+no+"次数执行");
                }
            },1,10, TimeUnit.SECONDS);
        }
    }
}

(3).SingleThreadPool

  1. 利用SingleThreadExecutor最多只能保证在本应用范围内,一个资源同时只会有一个线程在访问。
  2. 并不能保证其他应用不会对该资源进行访问
  3. 它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
  4. 结果依次输出,相当于顺序执行各个任务。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SingleThreadDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+",i:" + temp);
                }
            });
        }
    }
}

(4).FixedThreadPool

  1. 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  2. 定长线程池的大小最好根据系统资源进行设置
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FixedThreadDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int temp = i;
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
                    System.out.println(Thread.currentThread().getName()+",i:" + temp);
                }
            });
        }
    }
}

以上是四个已经定义的过的线程池

----------------------------------------------------分隔符----------------------------------------------------

那么接下来,见证奇迹的时候到了,自定义线程

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ExecutorsTest {
    public static void main(String[] args) {
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1,3,3, TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(5));
        poolExecutor.execute(new TaskThread("1"));
        poolExecutor.execute(new TaskThread("2"));
        poolExecutor.execute(new TaskThread("3"));
        poolExecutor.execute(new TaskThread("4"));
        poolExecutor.execute(new TaskThread("5"));
        poolExecutor.execute(new TaskThread("6"));
        poolExecutor.execute(new TaskThread("7"));
        poolExecutor.execute(new TaskThread("8"));
        poolExecutor.execute(new TaskThread("9"));
        poolExecutor.shutdown();
    }
}

class TaskThread implements Runnable{
    private String threadNmae;
    public TaskThread(String name){
        this.threadNmae = name;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+ " name= "+this.threadNmae);
    }
}

上面的代码中,

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1,3,3, TimeUnit.SECONDS,new LinkedBlockingDeque<>(5));

对应的源码:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {...}

即:核心线程数(corePoolSize)为1,最大线程数(maximumPoolSize)为3,线程池维护线程所允许的空闲时间 (keepAliveTime)为3,单位(unit)秒,阻塞队列(workQueue)为LinkedBlockingDeque<>(5);

扩展说明:

无论创建那种线程池 必须要调用ThreadPoolExecutor
线程池类为 java.util.concurrent.ThreadPoolExecutor,常用构造方法为: 
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 
          BlockingQueue workQueue, RejectedExecutionHandler handler) 
corePoolSize: 线程池维护线程的最少数量 maximumPoolSize:线程池维护线程的最大数量 keepAliveTime: 线程池维护线程所允许的空闲时间 unit: 线程池维护线程所允许的空闲时间的单位 workQueue: 线程池所使用的缓冲队列 handler: 线程池对拒绝任务的处理策略 一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。
当一个任务通过execute(Runnable)方法欲添加到线程池时: 
如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。 
如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。 
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。 
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
也就是:处理任务的优先级为: 

核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。 

拒绝处理时候会抛出异常:意思说当前执行的线程数总数 大于 线程池维护线程的最大数量 + 线程池所使用的缓冲队列所能容纳的最大线程数

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.example.study04.demo4.TaskThread@1be6f5c3 rejected from java.util.concurrent.ThreadPoolExecutor@6b884d57[Running, pool size = 3, active threads = 3, queued tasks = 3, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    at com.example.study04.demo4.ExecutorsTest.main(ExecutorsTest.java:17)

handler有四个选择: 

ThreadPoolExecutor.AbortPolicy()       抛出java.util.concurrent.RejectedExecutionException异常 
ThreadPoolExecutor.CallerRunsPolicy()    重试添加当前的任务,他会自动重复调用execute()方法 
ThreadPoolExecutor.DiscardOldestPolicy()  抛弃旧的任务 
ThreadPoolExecutor.DiscardPolicy()      抛弃当前的任务 

 

posted @ 2020-03-29 01:49  An-Optimistic-Person  阅读(150)  评论(0编辑  收藏  举报