谈谈JAVA多线程使用
在java开发中,当需求复杂度和并发量增大时,引入多线程来充分发挥机器的性能是很有必要的,但是引入多线程以后系统复杂度随之上升,使用不当带来OOM或者CPU疯狂飙升导致服务崩溃的风险增大,这时候理解多线程的使用变得尤为重要。下文谈谈我自身开发中,对java中使用多线程的理解。不过什么是线程,线程和进程的关系本文不再赘述。
1、提到多线程,就不得不提Thread类
在java语言基础库中,提供了一个Thread类,用来表示或操作线程,Thread类可以视为是Java标准库提供的API,Java是支持多线程编程的,在Java中创建好的Thread实例,其实就表示操作系统中存在的一个线程,是一一对应的关系,操作系统提供了一组关于线程的API(C语言),Java对于这组API进一步封装之后,把API变成适用java语言的各个方法,存在Thread类中。
查看Thread类的原码,我们可以看到几乎都是native方法,意味着底层是操作系统提供的c语言库函数
讯享网1)那么如何快速创建一个线程用来异步执行一些业务呢?
或许你也曾疑惑或正在疑惑,很多人说创建线程有3种方法,有的人说是4种,那么到底有几种?如何合理选择创建线程的方java多线程基础教学视频式
我们知道在Java中Thread和操作系统的线程一一对应,而JAVA是面向对象的编程语言,万物皆对象,线程肯定也是一个对象,我们能不能通过new一个Thread的实例来创建线程呢,如果你从这个思路来考虑,那么你已经和JAVA之父的思路在同一个频道上了,也就是说是可以这么来创建线程的
讯享网
但是你运行完会发现和没执行一样什么都没发生,为什么,这是因为我们没有让这个线程做事
当然,实际上继承Thread类只是其中一种创建线程的方式,我们来看看其他方案
a: 实现Runnable接口
讯享网
b: 通过Callable和Future接口创建线程

归纳:由此可见,不管使用哪一种方式,最后都要通过Thread类来维护,笔者认为实际创建线程的方式就一种,那就是new一个Thread对象。不过实现Runnable带来的好处是可以继承别的父类,以便于扩展,实现Callable,配合FutureTask可以实现获取执行的返回值和捕获执行异常的场景。
2、使用线程池来管理线程
在上文我们知道了创建线程的各种方式,那么为什么还要引入线程池的概念呢。
对比一下数据库连接池,作用无非是复用已有的连接,避免每次请求都重新建立连接,从而减少建立和断开连接的开销,提升数据库操作的响应速度和稳定性,还可以监控连接情况等。线程池其实也是差不多的作用。
线程池相关的类基本都在java.util.concurrent包下,翻阅原码可以看到是Doug Lea这个人一手编写,太牛了。
本文我们着重谈谈java.util.concurrent.ThreadPoolExecutor,因为只要你实例化这个对象出来,就已经创建好了一个线程池,剩下的就是按照业务需要丢线程进去执行
1)、如何创建线程池
通过介绍我们知道new ThreadPoolExecutor即可创建,但是看源码得知构造方法有很多,我们具体用哪个更合适呢
corePoolSize 核心线程池大小 - 表示该线程池有多少个一直可以循环使用不会被销毁的线程资源
maximumPoolSize 最大线程池大小 - 表示该线程池的线程总数,当核心线程数慢时,再有线程被添加时会进入对列等待,队列满时,线程池最大会创建(maximumPoolSize - corePoolSize)个非核心线程来执行新添加的线程
keepAliveTime 非核心线程空闲多久会被释放
unit 超时时间单位
workQueue 阻塞队列 - 核心线程满时存放线程的队列
threadFactory 线程工厂 - 可以通过自定义工厂来定义线程名等
defaultHandler 拒绝策略 - 当线程池被占满时通过什么策略拒绝
2)、通过对构造方法的7个参数的理解,创建适合的线程池来使用
3、通过使用现有的api创建线程池(不推荐)
注意到此方式创建的线程池是ExecutorService类型,为什么呢,有兴趣的同学可以看看ThreadPoolExecutor和ExecutorService的关系,有兴趣的朋友可以自己研究下
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/3609.html