为什么使用线程池
- 为了降低资源的消耗,通过重复利用已创建的线程来降低创建和销毁线程造成的资源消耗。
- 提高响应的速度。当任务到达时,任务可以不需要等到线程创建就立即执行。
- 提高线程的可管理性。线程是比较稀缺的资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以统一的调度和分配,调优和监控,当我们线程创建过多时,容易引发内存溢出,因此我们就有必要使用线程池的技术了。阿里禁止使用jdk自带的线程池,因为jdk的线程池是有缺陷的。
Executors类
JDK自带的四种线程池是通过Executors提供的
- newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,若无可回收,创建新线程。
- newFixedThreadPool:创建一个定长的线程池,可以控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool:创建一个定长的线程池,支持定时及周期性任务执行
- newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有的任务按照指定顺序执行
这四种线程池的初始化都调用了同一个构造器
ThreadPoolExecutor(int corePoolSize,
                    int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue<Runnable> workQueue,
                    ThreadFactory threadFactory,
                    RejectedExecutionHandler handler)参数的意义
- corePoolSize:线程池里线程的数量,核心线程池大小
- maximumPoolSize:指定了线程池里的最大线程数量
- keepAliveTime:当线程池线程数量大于- corePoolSize,多出来的空闲线程,多长时间被销毁
- unit:时间单位
- workQueue:任务队列,用于存放提交但是尚未被执行的任务
- threadFactory:线程工厂,用来创建线程,线程工厂就是我们- new线程的
- handler:拒绝策略,是将任务添加到线程池中时,线程池拒绝该任务多采取的相应的措施
常见的工作队列
ArrayBlockingQueue:基于数组的有界阻塞队列。FIFO。LinkedBlockingQueue:基于链表的有界阻塞队列。FIFO。
线程池提供了四种拒绝策略
- AbortPolicy:直接抛出异常,默认的策略。
- CallerRunPolicy:用调用者所在的线程来执行任务
- DiscardOldestPolicy:丢弃阻塞队列中最靠前的任务,并执行当前任务
- DiscardPolicy:直接丢弃任务
public class Ch01 {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        Runnable taskOne = () -> {
            System.out.println(Thread.currentThread().getName() + "taskOne...");
        };
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
        ExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 40; i++) {
            fixedThreadPool.submit(taskOne);
        }
    }
}自定义线程池
public class Ch02 {
    private static final AtomicInteger poolNumber = new AtomicInteger(1);
    private final ThreadGroup group;
    private final AtomicInteger threadNumber = new AtomicInteger(1);
    private final String namePrefix;
    Ch02(String name){
        SecurityManager s = System.getSecurityManager();
        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
        namePrefix = name + "-" + poolNumber.getAndIncrement() + "-thread-";
    }
    Ch02(){
        this("default");
    }
    public Thread newThread(Runnable r){
        // 就是在创建线程
        Thread t = new Thread(group,r,namePrefix + threadNumber.getAndIncrement(),0);
        if(t.isDaemon()){
            t.setDaemon(false);
        }
        if(t.getPriority() != Thread.NORM_PRIORITY){
            t.setPriority(Thread.NORM_PRIORITY);
        }
        return t;
    }
    public static void main(String[] args) {
        Ch02 ch02 = new Ch02();
        ch02.newThread(()->{
            System.out.println("自定义线程池创建的线程...");
        }).start();
    }
}两个线程轮流打印数字,从1-100
public class Test01 {
    private static class MyNumberTest {
        private static boolean flag = true;
        // 要打印的数字
        private static int count = 0;
        public synchronized void print1() {
            for (int i = 0; i < 50; i++) {
                while (!flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "->" + ++count);
                flag = !flag;
                notifyAll();
            }
        }
        public synchronized void print2() {
            for (int i = 0; i < 50; i++) {
                while (flag) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + "->" + ++count);
                flag = !flag;
                notifyAll();
            }
        }
    }
    public static void main(String[] args) {
        MyNumberTest myNumberTest = new MyNumberTest();
        Thread t1 = new Thread(() -> {
            myNumberTest.print1();
        });
        t1.setName("线程A");
        Thread t2 = new Thread(() -> {
            myNumberTest.print2();
        });
        t2.setName("线程B");
        t1.start();
        t2.start();
    }
}轮流打印数组内容
class Two extends Thread{
    int [] arr1 = new int[]{1,2,3,4,5};
    int [] arr2 = new int[]{-1,-2,-3,-4,-5};
    private static boolean flag = true;
    public synchronized void print1() {
        for (int i = 0; i < arr1.length; i++) {
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(arr1[i]);
            flag = !flag;
            notifyAll();
        }
    }
    public synchronized void print2() {
        for (int i = 0; i < arr2.length; i++) {
            while (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(arr2[i]);
            flag = !flag;
            notifyAll();
        }
    }
}
public class Test03 {
    public static void main(String[] args) {
        Two two = new Two();
        Thread t1 = new Thread(()->{
            two.print1();
        });
        Thread t2 = new Thread(()->{
            two.print2();
        });
        t1.start();
        t2.start();
    }
}尽量不要理会那些使你认为你不成功的疑虑,勇往直前,即使最后失败也要做做看,其结果往往并非真的会失败。 ——比尔·盖茨