JUC四-阻塞队列BlockingQueue,线程池(三大方法,七大参数,四种拒绝策略)

9.阻塞队列BlockingQueue

img

image-20220927101703742

什么时候会使用堵塞队列:多线程并发处理,线程池

四组API

方式抛出异常有返回值(T or F),不抛出异常阻塞,一直等待阻塞,超时等待
添加add()offer()put()offer(,,)
移除remove()pull()take()pull(,)
检测队首元素element()peek()--
public class TestBlockingQueue {
    public static void main(String[] args) throws InterruptedException {
        test4();
    }
    // 抛出异常:java.lang.IllegalStateException: Queue full
    public static void test1(){
        // 队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        // add()方法返回boolean值
        boolean flag1 = blockingQueue.add("a");
        boolean flag2 = blockingQueue.add("b");
        boolean flag3 = blockingQueue.add("c");
        // !!! add添加元素超过队列的长度会抛出异常java.lang.IllegalStateException: Queue full
        boolean flag4 = blockingQueue.add("d");
        System.out.println(blockingQueue.element());// 获得队首元素
        System.out.println("=========");
        // remove()返回本次移除的元素
        Object e1 = blockingQueue.remove();//a
        Object e2 = blockingQueue.remove();//b
        Object e3 = blockingQueue.remove();//c
        //!!!  队列中没有元素仍继续移除元素会抛出异常java.util.NoSuchElementException
        Object e4 = blockingQueue.remove();
    }
    // 有返回值,不抛出异常
    public static void test2(){
        // 队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        // offer返回boolean值
        boolean flag1 = blockingQueue.offer("a");
        boolean flag2 = blockingQueue.offer("b");
        boolean flag3 = blockingQueue.offer("c");

        //boolean flag4 = blockingQueue.offer("d");// offer添加元素超过队列的长度会返回false
        System.out.println(blockingQueue.peek());// 获得队首元素
        System.out.println("=========");
        // poll()返回本次移除的元素
        Object poll1 = blockingQueue.poll();
        Object poll2 = blockingQueue.poll();
        Object poll3 = blockingQueue.poll();
        Object poll4 = blockingQueue.poll();// 队列中没有元素仍继续移除元素会打印出null
    }
    // 阻塞,一直等待
    public static void test3() throws InterruptedException {
        // 队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        // put没有返回值
        blockingQueue.put("a");
        blockingQueue.put("b");
        blockingQueue.put("c");
        //blockingQueue.put("d");// put添加元素超过队列的长度会一直等待
        System.out.println("=========");
        // take()返回本次移除的元素
        Object take1 = blockingQueue.take();
        Object take2 = blockingQueue.take();
        Object take3 = blockingQueue.take();
        Object take4 = blockingQueue.take();// 队列中没有元素仍继续移除元素会一直等待
    }
    // 阻塞,超时等待
    public static void test4() throws InterruptedException {
        // 队列的大小为3
        ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
        // offer返回boolean值
        boolean flag1 = blockingQueue.offer("a");
        boolean flag2 = blockingQueue.offer("b");
        boolean flag3 = blockingQueue.offer("c");
        // offer添加元素超过队列的长度会返回false;并且等待指定时间后推出,向下执行
        boolean flag4 = blockingQueue.offer("d", 2, TimeUnit.SECONDS);
        System.out.println("=========");
        // poll()返回本次移除的元素
        Object poll1 = blockingQueue.poll();
        Object poll2 = blockingQueue.poll();
        Object poll3 = blockingQueue.poll();
        // 队列中没有元素仍继续移除元素会打印出null,等待指定之间后退出。
        Object poll4 = blockingQueue.poll(2,TimeUnit.SECONDS);
    }
}

SynchronousQueue同步队列

SynchronousQueue是BlockingQueue的一个实现类

没有容量。

进去一个元素,必须等待取出这个元素后,才能放下一个元素。put()、take()

10.线程池

线程池:三大方法,7大参数,4种拒绝策略

创建,销毁浪费资源

池化技术 优化资源的使用

事先准备好一些资源,有人用就来这里拿,用完后,还给我。

好处:

  • 降低资源的消耗
  • 提高响应速度
  • 方便管理

线程可以复用,可以控制最大并发量,管理线程

三大方法

Executors:执行人

线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。 说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
  主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
  主要问题是线程数最大数是Integer.MAX_VALUE(约为21亿),可能会创建数量非常多的线程,甚至OOM。

public interface Executor {
    void execute(Runnable command); //也是Runnable接口
public class demo1 {
    public static void main(String[] args) {

        //Executors工具类,三大方法
        // ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
        // ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定大小得线程池
        //ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩,线程数可变

        ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
        for (int i = 0; i < 10; i++) {
            //使用了线程池之后,使用线程池来创建线程
            threadPool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "ok");
            });
        }
        //线程池用完,程序结束,关闭线程池
        try {
            threadPool.shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
    }

}

每一个的执行结果:

 Executors.newSingleThreadExecutor();//单个线程      
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
pool-1-thread-1ok
 Executors.newFixedThreadPool(5);//创建一个固定大小得线程池
pool-1-thread-3ok
pool-1-thread-2ok
pool-1-thread-5ok
pool-1-thread-4ok
pool-1-thread-1ok
pool-1-thread-4ok
pool-1-thread-5ok
pool-1-thread-3ok
pool-1-thread-4ok
pool-1-thread-1ok
 ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩,线程数可变
pool-1-thread-2ok
pool-1-thread-1ok
pool-1-thread-3ok
pool-1-thread-10ok
pool-1-thread-8ok
pool-1-thread-9ok
pool-1-thread-5ok
pool-1-thread-6ok
pool-1-thread-4ok
pool-1-thread-7ok

七大参数

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
三大方法底层都调用得是ThreadPoolExecutor!!
    

不推荐使用的原因:

image-20220927171545335

//七个参数
    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.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
  • corePoolSize,//核心线程池大小 就是最小线程池大小

  • keepAliveTime:线程的最大生命周期,这里的生命周期有两个约束条件

    一:该参数针对的是超过corePoolSize数量的线程

    二:处于非运行状态的线程。即非核心线程数存活时间

  • 一般情况就是核心线程去处理

    当线程过来 阻塞队列等待(候客区)的都满了 才会去开启非核心线程(测过)

    如下图就是6个及以上 才会去创建非核心线程

  • 最大的承载就是阻塞队列+最大线程数

    如下图就是8个

  • 注意还有一个largestPoolSize,记录了曾经出现的最大线程个数。因为setMaximumPoolSize()可以改变最大线程数。

  • keepAliveTime 超时等待:下图 345是非核心线程 ,keepAliveTime 时间内没人使用就自动关闭了

image-20220927172328093

new ThreadPoolExecutor(2,
        5,
        3,
        TimeUnit.SECONDS,
        new LinkedBlockingDeque<>(3),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy());

image-20220927173820754

与上图对应的手动创建的 线程池

四种拒绝策略

new ThreadPoolExecutor.AbortPolicy(); // 抛出异常
new ThreadPoolExecutor.CallerRunsPolicy();// 哪来的去哪(主线程来的,就回去让主线程执行,)
new ThreadPoolExecutor.DiscardPolicy();// 丢掉任务,不抛出异常
new ThreadPoolExecutor.DiscardOldestPolicy();// 尝试和最早的竞争,竞争失败了也丢掉任务,也不抛出异常
for (int i = 0; i < 10; i++) {
    //使用了线程池之后,使用线程池来创建线程
    threadPool.execute(() -> {  CallerRunsPolicy 让主线程去跑里面的run方法,让主线程去代办 线程池不管了
        System.out.println(Thread.currentThread().getName() + "ok");
    });
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值