创建线程四种方法详解;及说明ThreadPoolExecutor方式创建线程池

2023-10-30

一:继承Thread类的方式

#创建一个线程
class MyThred extends Thread{
    public MyThred(String name) {
        super(name);
    }

    @Override
    public void run() {
     // 线程内的操作
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"  "+i);
        }
    }
}
# 启动线程
public class CtrateThread01 {
    public static void main(String[] args) {
        new MyThred("thread01").start();
    }
}
● 继承Thread类实现多线程方式的问题:
    Java只能单继承,所以一个类继承了Thread就不能再继承其它类。

二:实现Runnable接口

1,最繁琐的方式但最容易理解(创建类去实现Runnable接口)

# 创建一个类实现Runnable接口
public class CreateThreadRunable implements Runnable{
    @Override
    public void run() {
        for(int i=0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"  "+i);
        }
    }
    public static void main(String[] args) {
        CreateThreadRunable runable=new CreateThreadRunable();
        // 创建线程
        Thread myThread=new Thread(runable);
        // 启动线程
        myThread.start();
    }

2,匿名内部类实现

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<10;i++){
                    System.out.println(Thread.currentThread().getName()+"  "+i);
                }
            }
        }).start();
    }

3,Lambda表达式实现(由于Runnable接口是函数式接口)

    public static void main(String[] args) {
       new Thread(()->{
           for(int i=0;i<10;i++){
               System.out.println(Thread.currentThread().getName()+"  "+i);
           }
       }).start();

三 :FutureTask配合Callable接口

在这里插入图片描述

由上面的图片可以看出FutureTask类是实现了Runnable接口的。上面那一种方式正式实现Runnable接口并将
对象作为Thread的参数。那么显而易见可以new FutureTask() 作为Thread的参数实现创建线程。
不同的是FutureTask类需要一个参数Callable接口类型的对象(这时就只需要创建一个Callable的对象,
使用匿名内部类,Lambda表达式,或者创建一个类实现Callable接口 其一就能得到Callable类型的对象)
# 创建FutureTask对象
 FutureTask<Integer> futureTask=new FutureTask(new Callable() {
      @Override
      public Integer call() throws Exception {
           int result =10;
           /** call()方法是有返回值的,返回Object类型,也可以通过FutureTask<Integer>泛型指定
             并且返回的值可以通过FutureTask对象的get()取到
             */
           return result;
      }
 });
 public static void main(String[] args) {
   // 创建线程
	Thread myThread=new Thread(futureTask);
	// 启动线程
	myThread.start();
	// 获取返回值
	Integer value = futureTask.get();
	System.out.println(value);
	
}

四:使用线程池

Executors类创建线程池的常用方法:
[1] newCachedThreadPool()
● 执行很多短期异步任务,线程池根据需要创建多线程。并在先前创建的线程可用时将重用它们。可扩
容,遇强则强。
[2] newFixedThreadPool(int nThreads)
● 执行长期任务性能好,创建一个线程池,一池有N个固定的线程。
[3] newSingleThreadExecutor()
● 一个任务一个任务的执行,一池一线程。
public static void main(String[] args) {
	// 创建线程池(固定线程数量的方式)-参数为创建线程的个数
     ExecutorService threadPool = Executors.newFixedThreadPool(5);
     // 启动一个线程
     threadPool.execute(()->{
     System.out.println(Thread.currentThread().getName() + " " + new Date());
   });
}

五:意外情况

在这里插入图片描述

图片来自阿里巴巴开发规范,很明显上面的方式前三种显式创建线程和JDK自带java.util.concurrent.Executors
创建线程池的方式都被pass。

六,ThreadPoolExecutor方式(阿里推荐)

1,ThreadPoolExecutor的实例化七个参数:

 java.util.concurrent.ThreadPoolExecutor类的构造器(其一):

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;
}
构造器七个参数:
[1] corePoolSize:线程池中的常驻核心线程数
[2] maximumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
[3] keepAliveTime:多余的空闲线程的存活时间。当前池中线程数量超过corePoolSize时,当空闲时间
                  达到keepAliveTime的线程会被销毁,直到剩余线程数量等于 corePoolSize
[4] unit:keepAliveTime的时间单位
[5] workQueue:任务队列,被提交但尚未被执行的任务
[6] threadFactory:表示生成线程池中工作线程的工厂, 用于创建线程,一般默认的即可
[7] handler:拒绝策略处理器。当任务队列已满,工作线程也达到了maximumPoolSize,新增的工作
			任务将按照某个既定的拒绝策略被拒绝执行。

各参数理解
1.1 任务队列的类型BlockingQueue接口的七个实现类,创建线程时根据业务选择

[1] ArrayBlockingQueue:由数组结构组成的有界阻塞队列。
[2] LinkedBlockingQueue:由链表结构组成的有界(但大小默认值为integer.MAX_VALUE)阻塞队
列。
[3] PriorityBlockingQueue:支持优先级排序的无界阻塞队列。
[4] DelayQueue:使用优先级队列实现的延迟无界阻塞队列。
[5] SynchronousQueue:不存储元素的阻塞队列,也即单个元素的队列。
[6] LinkedTransferQueue:由链表组成的无界阻塞队列。
[7] LinkedBlockingDeque:由链表组成的双向阻塞队列。

1.2拒绝策略处理器,创建线程时根据业务选择

  一般我们创建线程池时,为防止资源被耗尽,任务队列都会选择创建有界任务队列,但这种模式下如果
出现任务队列已满且线程池创建的线程数达到你设置的最大线程数时,这时就需要你指定
ThreadPoolExecutor的RejectedExecutionHandler参数即合理的拒绝策略,来处理线程池“超载”的情
况。
ThreadPoolExecutor自带的拒绝策略如下:
[1] AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行
[2] CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是
                       将某些任务回退到调用者,从而降低新任务的流量。
[3] DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前
                         任务。
[4] DiscardPolicy:该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢
                   失,这是最好的一种策略。
以上内置的策略均实现了RejectedExecutionHandler接口,也可以自己扩展RejectedExecutionHandler
接口,定义自己的拒绝策略。

2,手写线程池

ThreadPoolExecutor方式自定义线程池同样是通过指定7个必要参数,创建ThreadPoolExecutor对象:
public class ThreadPoolDemo {
     public static void main(String[] args) throws InterruptedException {

        // 准备创建线程池所需要的7个参数
        int corePoolSize = 3;
        int maximumPoolSize = 5;
        int keepLiveTime = 10;
        TimeUnit timeUnit = TimeUnit.SECONDS;
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        ArrayBlockingQueue queue = new ArrayBlockingQueue<>(3);

        RejectedExecutionHandler policy =
                // 当触发拒绝策略所满足条件时会抛出异常:java.util.concurrent.RejectedExecutionException
                // new ThreadPoolExecutor.AbortPolicy();

                // 当触发拒绝策略所满足条件时会将任务转回调用者(main线程)执行
                // new ThreadPoolExecutor.CallerRunsPolicy();

                // 当触发拒绝策略所满足条件时会放弃等待时间最长的那个任务
                // new ThreadPoolExecutor.DiscardOldestPolicy();

                // 当触发拒绝策略所满足条件时会静默丢弃新的任务
                new ThreadPoolExecutor.DiscardOldestPolicy();

        // 创建线程池对象
        ThreadPoolExecutor myThreadPool = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepLiveTime,
                timeUnit,
                queue,
                threadFactory,
                policy);
        // 就可以使用我们自己的线程池,创建线程了
         myThreadPool.execute(() -> {
                while (true) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在工作");
                }
            });
         }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建线程四种方法详解;及说明ThreadPoolExecutor方式创建线程池 的相关文章

  • java.lang.VerifyError:JVMVRFY012堆栈形状不一致;

    在 WAS 8 5 5 中部署 Maven 项目时出现以下错误 我在WAS中安装了JDK 1 6和1 7 错误500 org springframework web util NestedServletException 处理程序处理失败
  • 如何在 IDEA Intellij 上使用 Spring-boot 自动重新加载

    我写了一个基于Spring boot tomcat freemarker的项目 我运行成功 但是每当我修改一些模板和java类时 我必须重新启动服务器或使用Intellij上的 重新加载更改的类 菜单才能使更改生效 浪费很多时间 然后我尝试
  • 策略模式还是命令模式?

    假设我有一个金融交易列表 我需要针对这些交易执行一系列验证规则 一个例子是我有一笔购买产品的交易 但是首先我需要验证交易中的帐户是否有足够的可用资金 产品没有售完等 由于这些规则 交易将是标记为拒绝 并应指定错误代码 当然 我正在考虑用一个
  • 在 Java 正则表达式中获取多个模式的重叠匹配

    我有同样的问题这个链接 https stackoverflow com questions 18751486 matching one string multiple times using regex in java 但有多种模式 我的正
  • 查询 MongoDB 集合中的字段。

    我正在尝试查询 mongodb 集合中的特定字段 这是我的代码和输出 Mongo m new Mongo DB db m getDB mydb DBCollection coll db getCollection student addin
  • 重写 getPreferredSize() 会破坏 LSP

    我总是在这个压倒一切的网站上看到建议getPreferredSize 而不是使用setPreferredSize 例如 如前面的线程所示 对于固定大小的组件 使用重写 getPreferredSize 而不是使用 setPreferredS
  • 迭代函数可以调用自身吗?

    当观看下面的 MIT 6 001 课程视频时 讲师在 28 00 将此算法标记为迭代 但是 在 30 27 他说这个算法和实际的 递归 算法都是递归的 该函数正在使用基本情况调用自身 那么这次迭代情况如何 private int itera
  • 即使在轴上进行自动量程调整,我也可以保留积分刻度线吗?

    我 偷 了一些代码here http fxexperience com 2012 01 curve fitting and styling areachart 拥有一个AreaChart我在 FXML 中使用了 平滑线条 它的工作原理如下
  • 在哪里保存选项值、重要文件的路径等[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我正在创建一个程序 需要设置一些选项值以及图像文件的一些路径 SQLite 数据库的路径 有关各种按钮上文本的一些信息 有关要使用哪个数据库的信
  • 如何在 MSSQL 中获取 CURRENT_DATE?

    我正在使用 jpa 3 o 和 Hibernate 我有一个命名查询 SELECT COUNT wt id FROM WPSTransaction wt WHERE wt createdDate gt CURRENT DATE WPSTra
  • 在java中将字符串日期转换为美国格式

    我有下面的代码 其中日期为字符串类型 我必须将其设置为美国格式 所以下面我已经展示了它 private static final SimpleDateFormat usOutputDate new SimpleDateFormat MM d
  • 可访问数据的 Java 约定。 (公共访问器和 Getter/命名)

    通过 Java API 您会看到大量冲突的命名和实践 这让我感到非常困惑 例如 The String http grepcode com file repository grepcode com java root jdk openjdk
  • 如何将 Java 地图转换为在 Scala 中使用?

    我正在开发一个 Scala 程序 该程序调用 Java 库中的函数 处理结果并生成 CSV 有问题的 Java 函数如下所示 Map
  • 插入时的 iBatis 判别器

    我有一个抽象类Example以及与之相伴的具体子类 我使用鉴别器来提取数据out数据库的 像这样
  • 在 Java 中创建 XML 文件的最佳方法是什么?

    我们目前使用 dom4j 来创建 XML 文件 不过 我猜现在有更好的东西了 如果我们使用的是 Java 1 6 或更高版本 那么在编写 XML 文件时最好使用什么类 运行速度最快 使用简单 我不需要构建一个 DOM 然后编写整个 DOM
  • 在 java 中运行外部应用程序但不要等待它完成

    我正在用java编写一个应用程序 允许我运行其他应用程序 为此 我使用了 Process 类对象 但当我这样做时 应用程序会等待进程结束 然后再退出 有没有办法在 Java 中运行外部应用程序 但不等待它完成 public static v
  • 嵌套字段的 Comparator.comparing(...)

    假设我有一个这样的域模型 class Lecture Course course getters class Course Teacher teacher int studentSize getters class Teacher int
  • BadPaddingException:无效的密文

    我需要一些帮助 因为这是我第一次编写加密代码 加密代码似乎工作正常 但解密会引发错误 我得到的错误是 de flexiprovider api exceptions BadPaddingException 无效的密文 in the 解密函数
  • 当底层连接是有状态时如何使用 Apache HttpClient?

    我在谷歌上搜索了很多关于如何使用 HttpClient 进行多线程处理的信息 他们中的大多数人建议使用 ThreadSafeClientConnManager 但我的应用程序必须登录某个主机 登录表单页面 以便 HttpClient 获得底
  • Java/MongoDB 按日期查询

    我将一个值作为 java util Date 存储在我的集合中 但是当我查询以获取两个特定日期之间的值时 我最终得到的值超出了范围 这是我的代码 插入 BasicDBObject object new BasicDBObject objec

随机推荐

  • MySQL子查询

    子查询指一个查询语句嵌套在另一个查询语句内部的查询 这个特性从MySQL 4 1开始引入 SQL 中子查询的使用大大增强了 SELECT 查询的能力 因为很多时候查询需要从结果集中获取数据 或者需要从同一个表中先计算得出一个数据结果 然后与
  • 微信小程序和百度的语音识别接口

    介绍 因为项目需要 使用到了微信小程序和百度的语音接口 现在将项目中的一个小模块拿出来单独分享 技术关键字 微信小程序 百度语音接口 nodejs express fluent ffmegp 环境 windows 10 vs code 1
  • adb inputswipe shell_adb shell 基本使用

    连接远程设备 adb connect ip host 端口 获取设备 adb devices 显示adb连接设备列表 adb e d s xxx shell e 模拟器 d 外置设备 s 输入序列号 进入shell后 adb shell 就
  • Qt之NSIS打包

    一 Qt发布方式 Qt发布的时候 通常使用两种方式 1 静态编译 把相关联的库一并引入可执行程序 虽然发布简单 但可执行程序较大 2 动态编译 把相关联的库 以dll的形式引用 不包含到可执行程序 发布不方便 但可执行程序较小 二 NSIS
  • leectode 合并二叉树 -- 递归

    0 题目描述 leetcode原题链接 617 合并二叉树 1 递归解法 可以使用深度优先搜索合并两个二叉树 从根节点开始同时遍历两个二叉树 并将对应的节点进行合并 两个二叉树的对应节点可能存在以下三种情况 对于每种情况使用不同的合并方式
  • 梯度下降(Gradient Descent)

    基本思想 梯度下降是一个用来求函数最小值的算法 本次 我们将使用梯度下降算法来求出代价函数的最小值 梯度下降背后的思想是 开始时我们随机选择一个参数的组合 计算代价函数 然后我们寻找下一个能让代价函数值下降最多的参数组合 我们持续这么做直到
  • Vue2的学习

    computed计算属性 概念 基于现有数据 计算出来的新属性 依赖的数据变化 会自动重新计算 语法 声明在computed配置项中 一个计算属性对应一个函数 这是一个属性 计算属性名 不是方法 注意不要忘记return div ul li
  • 抓取热门话题:获取热门话题及其讨论

    目录 1 抓取微博热门话题简介 2 准备工作 3 分析微博网站结构 4 编写微博热门话题爬虫
  • 【程序员面试金典】对于一个元素各不相同且按升序排列的有序序列,请编写一个算法,创建一棵高度最小的二叉查找树。

    题目描述 对于一个元素各不相同且按升序排列的有序序列 请编写一个算法 创建一棵高度最小的二叉查找树 给定一个有序序列int vals 请返回创建的二叉查找树的高度 class MinimalBST public int buildMinim
  • 简单的融合模型:基于keras 的少量样本集迁移学习 VGG16+MeanShift+PAC降维混合模型的苹果识别

    案例分析 更多是是一种思想 而不是具体实现 1 数据集 样本总数为30个 其中普通苹果和其他苹果各占一半 其中有10个苹果已经标注其他均无标签 2 数据集扩容 由于数据集中数据数量少无法满足模型训练 故而改变图片生成一部分模型 path o
  • 翻转字符串

    描述 写出一个程序 接受一个字符串 然后输出该字符串反转后的字符串 字符串长度不超过1000 示例1 输入 abcd 返回值 dcba 示例2 输入 返回值 法一 使用StringBulider public String solve St
  • UML实例

    以下内容摘自张海藩老师 软件工程导论 课件 UML实例 拟开发一软件 完成学校管理中的教务部门功能 包括班级管理 课程管理 帐户管理等 要求用UML建模 1 用例图设计 主用例图 班级管理子用例图 帐户管理子用例图 2 顺序图和用例图 可为
  • echarts图形销毁重新绘制

    echars在绘制图形的时候会给div添加属性 echarts instance 因此只需要将此属性移除并清空div内容即可重新绘制新的echarts图形 myChart removeAttr echarts instance empty
  • libevent库使用之二:深入理解使用

    目录 一 event base 1 创建event base 2 查看IO模型 3 销毁event base 4 事件循环 event loop 5 event base的例子 二 event 事件 1 创建一个事件event 2 释放ev
  • IE9下silverlight 里边MessageBox.Show 失效!

    今天刚刚安装了IE9 在用的时候发现之前用silverlight 做的一个页面里边 MessageBox Show 执行后看不到弹出的对话框 整个页面卡在哪儿没反应了 测试了一下发现是因为silverlight 所在的页面 是用 javas
  • 迁移wind to linux服务器EE网站--迁移说明步骤

    1 上传程序文件 htaccess上传 里面有特殊字符记得更改2 还原数据库从原数据库导出 SQL的命令mysqldump u用户名 p密码 default character set latin1 数据名 gt 数据名 sql3 修改配置
  • 用CSS画小猪佩奇,你就是下一个社会人!

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 作者 江志耿 腾讯TEG网络工程师 我是佩奇 哼 这是我的弟弟乔治 呱呱 这是我的妈妈 嚯 这是我的爸爸 嚯 背景 小猪佩奇已经火了好一阵了 其实一开始我是不屑的 纵观小朋友的历届动
  • 网络安全-子域名收集

    本文为作者学习文章 按作者习惯写成 如有错误或需要追加内容请留言 不喜勿喷 本文为追加文章 后期慢慢追加 子域名 子域名指二级域名 二级域名是顶级域名 一级域名 的下一级比如mail heetian com和bbs heetian com是
  • Fusionstorage Cinder架构

    由于最近一个月加班开发一个云存储产品 fusionstorage cinder 之前也没有碰过云存储这方面的知识 于是花了很长一段时间去学习了解它的架构 首先我们要知道云存储是什么 云存储其实是在云计算概念上延伸出的一个新概念 通过集群应用
  • 创建线程四种方法详解;及说明ThreadPoolExecutor方式创建线程池

    一 继承Thread类的方式 创建一个线程 class MyThred extends Thread public MyThred String name super name Override public void run 线程内的操作