java线程提交_从Java线程到线程池

线程模型

线程模型分为两类,用户级线程(ULT)和内核级线程(KLT)

用户级线程(ULT):user level threads,系统内核对ULT无感知,线程的创建和调度都由用户级APP进程管理;即APP自行管理的线程,就是用户级线程

内核级线程(KLT):kernel level threads,线程的创建,调度和切换上下文等,都由操作系统内核管理

如图所示,ULT模型中,每个进程创建的线程,均由自身进程维护管理,而KLT模型中,进程创建的线程,由系统内核进行维护管理。

94754986e532cad6b3df5f4adbfc1ec9.png

​在执行的区别之上,ULT和KLT最大的区别就是:ULT线程的调度不需要内核直接参与,控制简单,创建和销毁线程、线程切换代价等线程管理的开销比内核线程少得多。但是其资源调度按照进程进行,不能利用系统的多核处理,多个处理器下,同一个进程中的线程只能在同一个处理器下分时复用;KLT由内核进行调度,当有多个处理器时,一个进程的多个线程可以同时执行,但是KLT线程的创建和切换等开销很大。

​Java线程是依赖于系统内核,通过JVM调用系统库创建内核线程。Java的Thread和内核线程呈 1:1映射关系。by the way,这也是为什么我们需要线程池进行线程池化管理的原因。

b1d4f33dbd422964e141890b63cfa396.png

线程池

基础概念

​线程是程序运行的载体,说白了就是拥有cpu多长时间的执行权。而由于java线程是内核级线程带来的昂贵开销成本,在平时运用场景中我们也经常使用线程池对线程进行池化管理。线程池能为我们带来3大好处:

复用已创建的线程,降低创建销毁线程等带来的资源消耗

提高响应速度。线程早已创建好,不需要在等待线程创建就可以直接使用

可管理线程。由于线程是稀有资源,不能无限创建,因此用线程池能对线程进行统一规划,监控和分配

在线程池中,有几项概念最为重要:核心线程数,最大线程数,等待队列,饱和策略。它们的执行过程如下图。

8eab5c07a6e8ce22cfaee69e7c1dadef.png

为加强记忆,可以用工厂干活的方式理解。把核心线程数看作是正式工,当来了一堆任务的时候,正式工陆续开始干活,当任务增多的时候,正式工们手头上的任务还没干完,于是先放阻塞队列等待待会儿处理;后来任务量暴涨,阻塞队列也满了,于是就请一些临时工来干活,于是,正式工数+临时工数 = 最大线程数;再后来线程数持续增长,最大线程数也满了,只能做一些饱和策略限制任务的提交了。

线程池的使用

​我们可以通过new ThreadPoolExecutor的方式创建线程池。

//构造方法

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue)

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue,

ThreadFactory threadFactory)

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue,

RejectedExecutionHandler handler)

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueue workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler)

其中的参数需要说明下:

corePoolSize:核心线程数。线程池在最初阶段,池中线程数为0,当接收到一个任务后,就创建一个线程。即使之前的线程执行完毕空闲,新任务提交过来,依然会创建线程。直到创建线程到核心线程数。如果调用了prestartAllCoreThreads方法,那么线程池会预先创建好线程。

BlockingQueue: ⽤于保存等待执⾏的任务的阻塞队列,可参考JUC的7种阻塞队列,这里不再赘述

maximumPoolSize:线程池允许创建的最⼤线程数。如果队列满了,并且已创建的线程数⼩于最⼤线程数,则线程池会再创建新的线程执⾏任务

TimeUnit:线程活动保持时间的单位

keepAliveTime:线程活动保持时间。当线程池中创建的线程数量超过核心线程数,且有线程空闲超过该时间,空闲线程将会被回收至核心线程数大小。当设置为0,即只要线程空闲就立即回收

ThreadFactory:⽤于设置创建线程的⼯⼚,可以通过线程⼯⼚给每个创建出来的线程设置更有意义的名字。附录附上线程工厂的用法例子。

RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取⼀种策略处理提交的新任务。这个策略默认情况下是AbortPolicy。在JDK1.5中Java线程池框架提供了以下4种策略。

AbortPolicy:直接抛出异常。

CallerRunsPolicy:当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。

DiscardOldestPolicy:线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。

DiscardPolicy:不处理,丢弃掉。

当然也可以自定义,在附录举了一个demo可参考。

举上一个较为完整的线程池创建示例

BlockingQueue workQueue = new ArrayBlockingQueue(5);

ThreadPoolExecutor threadPoolExecutor =

new ThreadPoolExecutor(5, 10, 1000, TimeUnit.MILLISECONDS, workQueue, new ThreadPoolExecutor.AbortPolicy());

线程池的工作状态

线程池共有5种生命状态:RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED

b76c8a0aa2a755e610a415756dcb1b17.png

RUNNING:接受新任务并处理排队的任务

SHUTDOWN:不接受新任务,但处理排队的任务

STOP:不接受新任务,不处理排队的任务,中断正在进行的任务

TIDYING:所有任务都已终止,workerCount为零,将运行terminate()钩子方法

TERMINATED:线程池终止

线程池提交任务的方式有两种,分别为execute()和 submit()⽅法。

execute()⽅法⽤于提交不需要返回值的任务,⽆法判断任务是否被线程池执⾏成功。

submit()⽅法⽤于提交需要返回值的任务。线程池会返回⼀个future类型的对象,可通过future对象判断线程是否执行成功,获取返回值等。

线程池关闭的方式也有两种,shutdown()和shutdownNow()⽅法可关闭线程池。它们的原理是遍历线程池中的⼯作线程,然后逐个调⽤线程的interrupt⽅法来中断线程,所以⽆法响应中断的任务可能永远⽆法终⽌。

区别在于,shutdownNow 更改状态成STOP,然后尝试停⽌所有的正在执⾏或暂停任务的线程,并返回等待执⾏任务的列表,⽽shutdown更改状态成SHUTDOWN状态,然后中断所有没有正在执⾏任务的线程,正在执行的线程会继续执行完毕。

1.线程池设置多少合适:

2. 线程工厂的demo

/**

* 实现线程工厂的接口,然后实现自定义内容。重写newThread方法

*/

public class MyThreadFactory implements ThreadFactory {

private static int COUNTER = 0;

private static String THREAD_PREFIX = "myThread";

@Override

public Thread newThread(Runnable r) {

int i = COUNTER++;

return new Thread(r, THREAD_PREFIX + i);

}

//使用

public static void main(String[] args) {

MyThreadFactory myThreadFactory = new MyThreadFactory();

Thread thread = myThreadFactory.newThread(new Runnable() {

@Override

public void run() {

}

});

thread.start();

}

}

2. 自定义饱和策略

//需要实现RejectedExecutionHandler,重写rejectedExecution方法

class MyRejected implements RejectedExecutionHandler {

public MyRejected() {

}

@Override

public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

System.out.println("现线程池中的情况为:" + executor.getActiveCount());

System.out.println("当前被拒绝任务为:" + r.toString());

}

}

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

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

相关文章

使用Spring Boot自动发布和监视API

如果您正在沿着微服务风格的架构前进,那么您将需要接受的一个租户就是自动化。 这种架构风格介绍了许多活动部件。 如果成功,您的环境将具有大量服务API,企业可以将其用于应用程序开发和集成。 这意味着必须有一种方法可以发现可用的API文档…

mysql导入导出

导出1.将数据库mydb导出到e:\mysql\mydb.sql文件中:打开开始->运行->输入cmd 进入命令行模式c:\>mysqldump -h localhost -u root -p mydb >e:\mysql\mydb.sql然后输入密码,等待一会导出就成功了,可以到目标文件中检查是否成功。…

mysql 半同步关闭_MySQL的半同步模式配置

1、什么是半同步?在有一台主服务器、多台从服务器的情况下,主服务器只会等待一台从服务器同步数据。2、为什么要使用半同步?在使用同步模式时,数据的写速度太慢。在使用异步模式时,可能会造成从服务器上的现在存储的数…

GIS集成技术之二:数据集成

一。数据驱动。疑惑:ado.net作为一种通用的数据技术,适用与各种格式的文件各种格式的数据库,为一种通用的编程模型。GIS也提出数据集成:毫无疑问,不陷于某击中数据库。因此,我觉得GIS的中心是数据驱动&…

mysql中的replication_mysql中replication的相关问题总结

首先,要使用mysql中的replication,则需要配置master的my.cnf。例如:复制代码 代码示例:server-id 1log_bin mysql-bin#log_bin /var/log/mysql/mysql-bin.logexpire_logs_days 10max_binlog_size 100M#binlog_do_db include_database_na…

rest spring_带有Spring的REST的ETag

rest spring1.概述 本文将重点介绍ETag – Spring支持,RESTful API的集成测试以及带有curl的使用场景。 这是关于使用Spring 3.1和Spring Security 3.1和基于Java的配置来建立安全的RESTful Web服务的系列文章的第9篇。 REST with Spring系列: 第1部分 …

MySQL最早版本源码_MySQL旧版本升级为新版本

一:从版本3.23升级到4.104.10新特性:支持事务处理和存储过程升级过程的注意事项:1:升级采用直接复制安装文件的方法,简单实用,但要注意相关的配置更改; 2:直接复制备份的数据库不能通过复制的方法恢复&…

关于国产科学软件的思考(转)

转自 http://blog.pfan.cn/eMath/24264.html 作者 爱数学 http://blog.pfan.cn/eMath 原文如下: 这一段一直在问自己这个问题:“在我们常用的科学计算软件当中,有多少国产的?”,在记忆里面搜索了很久,似乎…

每个私有静态方法都是新类的候选人

您是否有私有的静态方法来帮助您将算法分解为更小的部分? 我做。 每次编写新方法时,我都会意识到它可以是一个新类。 当然,我不会从所有课程中选修课程,但这是目标。 私有静态方法不可重用,而类则可重用,这…

448. Find All Numbers Disappeared in an Array

一、题目 1、审题  2、分析 一个整形数组!元素值为 1~size; 出现的元素次数为 1~2 次。 求出所有 1~size 中没有出现的整数! 二、解答 1、思路 由于元素值都为 1~size之间。所以可以将数组下标 index 进行联系。 ① 遍历数组,将出现的元素值…

枚举:如何正确使用name()和toString()方法

两种方法之间的区别? Java枚举有两种方法来检索枚举常量的值: name()和.toString() 。 toString()方法调用name()方法,该方法返回枚举常量的字符串…

gradle maven_Gradle – Maven的观点

gradle maven正如我博客的读者所知道的, 我有点像Maven迷 。 我从2007年8月左右开始使用Maven,从没有回过头。 但是,与其他所有情况一样,“变化是唯一的常数”。 现在这个领域还有其他参与者,Gradle似乎是最有前途的。…

JDK 9中已弃用Java的Observer和Observable

在博客文章《 应用JDK 9 Deprecated增强功能》中 ,我讨论了JDK 9中 Deprecated批注中对forRemoval()和since()可选元素(方法)的添加 。 我在那篇文章中说:“在Java SE API上应用新的…

理解依赖注入(IOC)和学习Unity

IOC:英文全称:Inversion of Control,中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection)。 作用:将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调…

java中怎样验证重复文件_java – 如何在下载之前检查URL中的重复文件

如果您有基本URL并存储具有相同文件名的文件.由于文件修改时间和If-Modified-Since HTTP Header,您可以询问服务器是否值得再次下载映像.File f new File();// the file to downloadHttpURLConnection con (HttpURLConnection) new URL("http://www.test.com/"f.ge…

Jason是炮王

Jason是炮王 转载于:https://www.cnblogs.com/TankJam/p/11203636.html

事件传递 java_将事件传递/发送到父组件?

在Angular中,我可以创建一个发出动作的子组件:Component({...template: Click Me})export class ChildComponent {Output() onChildAction new EventEmitter();childAction() {this.onChildAction.emit();}}以及处理它的父组件 . 就像是:Com…

mongodb身份验证_MongoDB身份验证

mongodb身份验证我最近更新了Mongometer ,使其更加灵活。 发布新版本后不久,其中一位用户通过在帖子中发表评论来反馈问题。 我启动了我的机器,打开了我的IDE,发现了问题,并在半小时内将修补程序推送到了github 。 这不…

mysql列类型

http://hi.baidu.com/b37798969/item/429fb25f838f1d3233e0a99b MySQL支持大量的列类型,它可以被分为3类:数字类型、日期和时间类型以及字符串(字符)类型。本节首先给出可用类型的一个概述,并且总结每个列类型的存储需求,然后提供…

Java13的API_JAVA基础--JAVA API常见对象(其他API)13

一、其他API1.System类system类中的方法和成员变量都是静态的, 不需要创建System对象就可以直接使用。1 /*2 * 演示System的使用3 */4 public classSystemDemo {5 public static voidmain(String[] args) {67 /*8 * System类中的静态成员变量: out 和 er…