JUC-线程池

news2024/10/11 3:52:06

阻塞队列

概述和架构

分类和核心方法

这里是在讲 为了区分在不同场景下 调用的不同组实现方法

核心方法演示

package com.example.juc.queue;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

public class BlockingQueueDemo {

    public static void main(String[] args) throws InterruptedException {

        BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);

        // 第一组
//        System.out.println(blockingQueue.add("a"));
//        System.out.println(blockingQueue.add("b"));
//        System.out.println(blockingQueue.add("c"));
//        System.out.println(blockingQueue.element());

        // Exception in thread "main" java.lang.IllegalStateException: Queue full
//        System.out.println(blockingQueue.add("d"));

//        System.out.println(blockingQueue.remove());
//        System.out.println(blockingQueue.remove());
//        System.out.println(blockingQueue.remove());
        // Exception in thread "main" java.util.NoSuchElementException
//        System.out.println(blockingQueue.remove());


        // 第二组
//        System.out.println(blockingQueue.offer("a"));
//        System.out.println(blockingQueue.offer("b"));
//        System.out.println(blockingQueue.offer("c"));
//        // a
//        System.out.println(blockingQueue.peek());
//
//        // false
//        System.out.println(blockingQueue.offer("d"));
//
//        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());
//        System.out.println(blockingQueue.poll());
//        // null
//        System.out.println(blockingQueue.poll());

        // 第三组
//        blockingQueue.put("a");
//        blockingQueue.put("b");
//        blockingQueue.put("c");
//        // 会阻塞住 由于用的是定长的 ArrayBlockingQueue
        blockingQueue.put("www");
//
//
//        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());
//        System.out.println(blockingQueue.take());
//        // 阻塞
//        System.out.println(blockingQueue.take());

        // 第四组
        System.out.println(blockingQueue.offer("a"));
        System.out.println(blockingQueue.offer("b"));
        System.out.println(blockingQueue.offer("c"));
        // 阻塞 3S 后退出 返回 false
//        System.out.println(blockingQueue.offer("w", 3L, TimeUnit.SECONDS));


        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        System.out.println(blockingQueue.poll());
        // 阻塞 3S 后退出 返回 null
        System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS));

    }
}

线程池

概念

接口介绍以及提交任务方式对比

Executor

我们把实现了 Runnable或者 Callable接口的任务提交给线程池

Executor框架负责任务的执行

提交任务可以使用 submitexecute

ExecutorService 中 execute 和 submit 的区别

ExecutorService 中的 execute 和 submit 方法都用于提交任务,但它们有一些关键区别:

1.返回类型:

execute(Runnable command): 这个方法没有返回值。它只接受一个 Runnable 对象并执行它。

submit(Callable task): 这个方法返回一个 Future 对象。它可以接受一个 Callable 对象或一个 Runnable 对象,并返回一个 Future,可以用来检查任务的状态或获取任务的结果。

  1. 异常处理:

execute: 如果任务在执行过程中抛出未捕获的异常,异常会直接传播到调用者线程。

submit: 如果任务在执行过程中抛出未捕获的异常,异常会被捕获并存储在返回的 Future 对象中。调用 Future.get() 方法时会抛出 ExecutionException,其 getCause() 方法返回实际的异常。

任务类型:

execute: 只能接受 Runnable 对象。

submit: 可以接受 Runnable 或 Callable 对象

public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);

        // 使用 execute 提交任务
        threadPool.execute(() -> {
            System.out.println(Thread.currentThread().getName() + " 使用 execute 办理业务");
        });

        // 使用 submit 提交任务
        Future<String> future = threadPool.submit(() -> {
            System.out.println(Thread.currentThread().getName() + " 使用 submit 办理业务");
            return "任务完成";
        });

        try {
            // 获取 submit 任务的结果
            String result = future.get();
            System.out.println("submit 任务结果: " + result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }

总结: execute 功能较简单,submit 可以看做增强版本,可以获取一个 future

ScheduledThreadThreadPoolExecutor添加了调度任务执行的功能

常见线程池和创建线程池的底层原理

package com.example.juc.pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

// 演示线程池 三种 常用分类
public class ThreadPoolDemo1 {

    public static void main(String[] args) {
        // 一池五线程
        ExecutorService threadPool1 = Executors.newFixedThreadPool(5);

        // 一池一线程
        ExecutorService threadPool2 = Executors.newSingleThreadExecutor();

        // 一池可扩容线程
        ExecutorService threadPool3 = Executors.newCachedThreadPool();


        // 10 个顾客请求
        try {
            for (int i = 0; i <= 10; i++) {
                // 执行
                threadPool3.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " 办理业务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool3.shutdown();
        }

    }
}

底层都是创建 ThreadPoolExecutor

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

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

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }


// 引出下面的一小节,ThreadPoolExecutor 总共有 七个参数
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • newFixedThreadPool
    • 没有救急线程,也就无需空闲时间,阻塞队列无限
    • 适合任务量已知,相对耗时任务
  • newSingleThreadExecutor
    • 希望多个任务排队执行,线程数固定一个,多余任务排队执行
  • newCachedThreadPool
    • 全部是救急线程,60s空闲回收时间,救急线程无限创建
    • 适合任务比较密集,任务执行时间短

七个参数介绍

重点注意 keepAliveTIme 和 unit ,是用于救急线程在空闲后的回收

常用阻塞队列

  • 容量为 Integer.MAX_VALUE<font style="color:#DF2A3F;">LinkedBlockingQueue</font>(无界队列):FixedThreadPoolSingleThreadExectorFixedThreadPool最多只能创建核心线程数的线程(核心线程数和最大线程数相等),SingleThreadExector只能创建一个线程(核心线程数和最大线程数都是 1),二者的任务队列永远不会被放满。
public class LinkedBlockingQueueExample {
    public static void main(String[] args) {
        // 创建一个容量为 5 的 LinkedBlockingQueue 队列
        LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(5);
        
        // 创建生产者线程
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    String element = "Element-" + i;
                    System.out.println("Producer is putting: " + element);
                    queue.put(element);  // 阻塞直到有空间可放入元素
                    System.out.println("Producer has put: " + element);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 创建消费者线程
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("Consumer is waiting to take an element...");
                    String element = queue.take();  // 阻塞直到有元素可取
                    System.out.println("Consumer has taken: " + element);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });

        // 启动生产者和消费者线程
        producer.start();
        consumer.start();
    }
}

  • <font style="color:#DF2A3F;">SynchronousQueue</font>(同步队列):CachedThreadPoolSynchronousQueue 没有容量,不存储元素,插入时阻塞,直到元素被取出。
  • DelayedWorkQueue(延迟阻塞队列):ScheduledThreadPoolSingleThreadScheduledExecutorDelayedWorkQueue 的内部元素并不是按照放入的时间排序,而是会按照延迟的时间长短对任务进行排序,内部采用的是“堆”的数据结构,可以保证每次出队的任务都是当前队列中执行时间最靠前的。DelayedWorkQueue 添加元素满了之后会自动扩容原来容量的 1/2,即永远不会阻塞,最大扩容可达 Integer.MAX_VALUE,所以最多只能创建核心线程数的线程。
  • ArrayBlockingQueue: 有界阻塞队列,内部是一个数组。需要指定队列的容量。适用于有界任务队列的场景。
  • PriorityBlockingQueue:支持优先级排序的无界阻塞队列。元素按照优先级顺序出队。适用于需要任务优先级调度的场景。

工作流程和拒绝策略

  1. 如果当前运行的线程数小于核心线程数,那么就会新建一个线程来执行任务。
  2. 如果当前运行的线程数等于或大于核心线程数,但是小于最大线程数,那么就把该任务放入到任务队列里等待执行。
  3. 如果向任务队列投放任务失败(任务队列已经满了),但是当前运行的线程数是小于最大线程数的,就新建一个线程来执行任务。
  4. 如果当前运行的线程数已经等同于最大线程数了,新建线程将会使当前运行的线程超出最大线程数,那么当前任务会被拒绝,拒绝策略会调用RejectedExecutionHandler.rejectedExecution()方法。

自定义线程池

package com.example.juc.pool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

// 自定义线程池
public class ThreadPoolDemo2 {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2,
                5,
                2L,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        // 10 个顾客请求
        try {
            for (int i = 0; i <= 150; i++) {
                // 执行
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + " 办理业务");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2203978.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构哈夫曼树-哈夫曼树代码构造实现(C语言)

#define _CRT_SECURE_NO_WARNINGS 1 #include<stdlib.h> #include<stdio.h> #define N 30 //叶子结点的最大值 #define M 2*N-1 // 结点总数 typedef struct HTNode {int weight;int parent;int Lchild;int Rchild;int flag; }HTNode,HuffmanTree[M1];//Huffman…

2024年腾讯外包面试题(微创公司)

笔试&#xff1a; 1、判断异步执行顺序console.log(1);setTimeout(()>{Promise.resolve().then(()>{console.log(2);})console.log(3);},0);new Promise ((resolve)>{for(let i0; i<1000;i ){if(i1000){resolve();}}console.log(4);}).then(()>{console.log(5);…

不用PS!patchwork快速解决多子图组合问题~~

如果现在你还是将自己制作的图表放在PS或者PPT中进行随意组合的化&#xff0c;那么这篇文章你就得好好看看了&#xff0c;今天小编就给大家安利一个超强的突变自由组合包-patchwork&#xff0c;让你轻松实现多图的自由组合。 更多详细的数据可视化教程&#xff0c;可订阅我们的…

粗糙表面仿真和处理软件

首款基于粗糙表面的仿真和处理软件&#xff0c;该软件具有三种方法&#xff0c;主要是二维数字滤波法&#xff0c;相位频谱法和共轭梯度法。可以分别仿真具有高斯和非高斯分布的粗糙表面&#xff0c;其中非高斯表面利用Johnson转换系统进行变换给定偏度和峰度。对生成的粗糙表面…

怎么把视频转换成音频?深受大家喜欢的6个转换方法

怎么把视频转换成音频&#xff1f;在这个数字化迅速发展的时代&#xff0c;视频和音频已经成为我们生活中不可或缺的一部分。我们通过各种平台观看电影、听音乐、学习知识&#xff0c;视频内容承载着丰富的信息和情感。然而&#xff0c;有时候我们并不需要画面&#xff0c;而仅…

SpringBoot美发门店系统:智能库存管理

3系统分析 3.1可行性分析 通过对本美发门店管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本美发门店管理系统采用SSM框架&#xff0c;JAVA作为开发语…

JavaScript 常量/数据类型/类型转换 简单学习

目录 1. 常量 1.1 常量概述 1.2 案例 1.3 总结 2. 数据类型 2.1 概述 2.2 分类 2.2.1 基本数据类型 2.2.1 基本数据类型——number (数值/字型) 2.2.1 数字型——算术运算符 2.2.1 基本数据类型——String (字符串类型) 2.2.1 字符串拼接 2.2.1 模板字符串 2.2.1…

数据中心运维挑战:性能监控的困境与智能化解决方案的探寻

随着数字化进程的加速&#xff0c;数据中心已成为企业信息架构的核心支撑&#xff0c;其运维管理的复杂度和重要性也随之提升。运维团队需应对设备老化、资源分配失衡、性能波动等多重难题&#xff0c;以确保数据中心持续高效运行。 其中&#xff0c;性能监控作为运维管理的关键…

如何实现异地组网?最简单的方法与实用技巧

随着远程办公、跨地域团队协作以及家庭网络需求的增加&#xff0c;异地组网已成为许多人关注的焦点。异地组网的目的是让位于不同地点的设备可以通过互联网实现安全、稳定的连接&#xff0c;从而共享数据和资源。本文将详细介绍几种常见且简便的异地组网方法&#xff0c;包括使…

智慧园区平台项目建设方案

随着信息技术的飞速发展&#xff0c;智慧园区作为智慧城市的重要组成部分&#xff0c;正逐渐成为推动城市可持续发展的关键力量。本文旨在探讨智慧园区平台项目的建设内容&#xff0c;以期为相关领域的专家学者和决策者提供参考。 1. 智慧园区的定义与重要性 智慧园区是指运用…

C++设计模式——代理模式

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 引言代理模式的定义代理模式的具体实现 引言 我们经常听到代理服务器「代理服务器是一个中间服务器&#xff0c;能够接收客户端的请求&#xff0c;并代表客户端向服务器发起请求&#xff0c;然后将服…

计算、通信、感知与量子技术国际学术会议

第三届计算、通信、感知与量子技术国际会议&#xff08;CCPQT 2024&#xff09;将于2024年10月25日-10月27日在中国珠海召开&#xff0c;聚焦感知、绿色通信等领域&#xff0c;邀请国内外专家探讨前沿动态&#xff0c;旨在促进学术交流与产学研合作&#xff0c;推动学科融合发展…

YOLOv11改进策略【损失函数篇】| 利用MPDIoU,加强边界框回归的准确性

一、背景 目标检测和实例分割中的关键问题&#xff1a; 现有的大多数边界框回归损失函数在不同的预测结果下可能具有相同的值&#xff0c;这降低了边界框回归的收敛速度和准确性。 现有损失函数的不足&#xff1a; 现有的基于 ℓ n \ell_n ℓn​范数的损失函数简单但对各种尺度…

【LLM论文日更】| BGE经典论文-CPACK

论文&#xff1a;https://arxiv.org/pdf/2309.07597代码&#xff1a;GitHub - FlagOpen/FlagEmbedding: Retrieval and Retrieval-augmented LLMs机构&#xff1a;BAAI领域&#xff1a;embedding model发表&#xff1a;SIGIR 2024 ​ 研究背景 研究问题&#xff1a;这篇文章…

第十一章:规划过程组(11.18规划风险管理--11.24规划干系人参与)

前面几次考试几乎都考了风险管理的相关内容和试题~&#xff01;尤其是下午题所以感觉还是挺重要的&#xff01; 11.18 规划风险管理 11.18.1 风险基本概念 每个项目都在两个层面上存在风险:一是每个项目都有会影响项目达成目标的单个风险;二是由单个风险和不确定性的其他来源联…

RandLA-Net PB C++

tensorflow pb 模型 实现 c++ 部署 Code: https://github.com/QingyongHu/RandLA-Net RandLA-Net PB C++ randlanet_tf.h #ifndef RANDLANET_TF_H_

人工智能在免疫组化以及虚拟多重免疫荧光染色中的应用|文献速递·24-10-10

小罗碎碎念 这期推文准备了四篇文章&#xff0c;覆盖了AI在免疫组化、多重免疫组化以及虚拟多重免疫荧光染色中的应用。 目前来看&#xff0c;免疫组化这些技术大多用于验证&#xff0c;那么我们是否可以把从免疫组化分析得到的结论作为模型的先验知识&#xff0c;或者直接进…

vue3中 a-table设置某一个单元格的背景颜色

需求&#xff1a;根据某一个单元格中的某个条件不同&#xff0c;设置动态的颜色&#xff1b; 思路&#xff1a;通过官方文档提供的customCell进行判断设置不同的颜色背景&#xff0c;案例中进行了简单的行列判断&#xff0c;同学们可以根据自己的需求修改判断条件&#xff0c;动…

知乎信息流广告开户是啥政策?

作为国内领先的知识分享平台&#xff0c;知乎以其高质量的内容和精准的用户群体&#xff0c;成为了品牌营销的新蓝海。为了帮助更多企业抓住这一机遇&#xff0c;云衔科技正式推出知乎信息流广告开户及代运营服务&#xff0c;旨在为企业提供一站式的营销解决方案。 一、为什么…

mapbox解决wmts请求乱码问题

贴个群号 WebGIS学习交流群461555818&#xff0c;欢迎大家 事故现场 如图所示&#xff0c;wmts请求全是乱码&#xff0c;看起来像是将一个完整的请求拆成一个一个的字母了&#xff0c;而且控制台打印map.getStyle() 查看该source发现不出异常 解决办法 此类问题就是由于更…