只有光头才能变强。文本已收录至个人GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3yjava
在上周总结了一篇「工做中经常使用到的Java集合类」,反响还不错。这周来写写Java另外一个重要的知识点:「多线程」git
多线程你们在初学的时候,对这个知识点应该有很多的疑惑的。我认为主要缘由有两个:github
这就会给人带来一种感受「这破玩意涉及的东西是真的广,平时也不怎么用,怎么面试就恰恰爱问这个鬼东西」面试
很少BB,我要开始了。数据库
首先,咱们要明确的是「为何要使用多线程」,可能有人会认为「使用多线程就是为了加快程序运行的速度啊」。若是你是这样回答了,那面试官可能会问你「那多线程是怎么加快程序运行速度的?」后端
于个人理解:使用多线程最主要的缘由是提升系统的资源利用率。安全
如今CPU基本都是多核的,若是你只用单线程,那就是只用到了一个核心,其余的核心就至关于空闲在那里了。微信
厕所的坑位有5个,若是只用一个坑位,那不是很亏?好比如今我有5我的要上厕所。在单线程的时候:进去一我的解决要10分钟,而后后面的人都得等一个坑位。那总的时间就要花费50分钟。多线程
在多线程的时候,进去一我的要解决10分钟,而后后面的人发现还有别的坑位,就去别的坑位了,不是傻瓜地等一个坑位。框架
咱们能够把「等坑位」看做是IO操做,众所周知IO操做相对于CPU而言是很是慢的,CPU等待IO那段时间是空闲的。若是咱们须要作相似IO这种慢的操做,能够开多个线程出来,尽可能不要让CPU空闲下来,提升系统的资源利用率。
说白了,咱们就是在「压榨」CPU的资源。原本就有的资源,若是有须要,咱们就应当好好利用。
多线程不是银弹,并非说线程越多,咱们的资源利用效率就越好。执行IO操做咱们线程能够适当多一点,由于不少时候CPU是相对空闲的。若是是计算型的操做,原本CPU就不空闲了,还开不少的线程就不对了(有多线程就会有线程切换的问题,线程切换都是须要耗费资源的)
多线程其实离咱们很近,只是不少时候咱们感知不到它的存在而已。
Tomcat我相信每一个Java后端的同窗都认识它,它就是以多线程去响应请求的,咱们能够在server.xml
中配置链接池的配置,好比:
<Connector port="8080" maxThreads="350" maxHttpHeaderSize="8192" minSpareThreads="45" maxPostSize="512000" protocol="HTTP/1.1" enableLookups="false" redirectPort="8443" acceptCount="200" keepAliveTimeout="15000" maxKeepAliveRequests="-1" maxConnections="25000" connectionTimeout="15000" disableUploadTimeout="false" useBodyEncodingForURI="true" URIEncoding="UTF-8" />
Tomcat处理每个请求都会从线程链接池里边用一个线程去处理,这显然是多线程的操做。而后这个请求线程顺藤摸瓜到了咱们的Servlet,执行对应的service()
方法。
而咱们的service
方法是无状态的,多个线程请求service
方法,每每都没有操做共享变量,不操做共享变量就不会有线程安全问题。
上面只是用了Servlet举例,咱们经常使用的SpringMVC其实也是同样的(毕竟底层仍是Servlet)。
还有咱们在链接数据库的时候,也会用对应的链接池(Druid、C3P0、DBCP等),好比常见的Druid配置:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc_url}" /> <property name="username" value="${jdbc_user}" /> <property name="password" value="${jdbc_password}" /> <property name="filters" value="stat" /> <property name="maxActive" value="20" /> <property name="initialSize" value="1" /> <property name="maxWait" value="60000" /> <property name="minIdle" value="1" /> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <property name="minEvictableIdleTimeMillis" value="300000" /> <property name="testWhileIdle" value="true" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="poolPreparedStatements" value="true" /> <property name="maxOpenPreparedStatements" value="20" /> <property name="asyncInit" value="true" /> </bean>
我想说的是:咱们平常开发的程序几乎都是多线程模式的,只是绝大多数时候咱们没感知到而已。不少时候都是框架帮咱们屏蔽掉了。
从上面总结下来,咱们能够发现:咱们平常「关于多线程的代码」写得很少,可是咱们写的程序代码的的确确是在多线程的环境下跑的。
若是咱们不懂多线程知识,很直接的一个现实:
从文章最开头的思惟导图,咱们能够发现多线程的知识点仍是不少的,咱们起码得知道:
虽然在工做中未必会所有用得上,但若是项目真的用到了,咱们若是学过了可能就能够很快地理解当时为何要这样设计(我以为去挖掘过程仍是挺有意思的)。
「我可能不用,但你必需要有」
这个道理也很容易懂:「我买电脑的时候,虽然我是木耳听不出什么音质出来,但你音质就是得好」。企业招人的时候也同样「你在工做的时候未必要写,但你必需要会」
至少在我看来,从求职的角度触发,多线程是很重要的。以前我还整理过在我当时校招常常被问到的多线程面试题目:
原本是打算这篇文章主旋律就写这块的,而后我翻了一下本身维护的系统,用到的线程的地方还真的不是不少...
我就拿我如今的系统用到线程相关知识的几个例子吧。
我这边有个调度系统,运营设置了对应的时间,该任务就去执行,执行的内容大体就是去读HDFS文件,而后将数据组装,再传递到下游。
任务触发了之后,咱们直接将这个任务交给一个线程池去处理,交由线程池后就直接返回SUCCESS
。
这样作的好处是什么?若是多个任务同时触发,那可能某些任务执行时间过长,请求可能会被阻塞住,而咱们若是放在线程池中能够提升系统的吞吐量。
使用线程池的时候,每每咱们的调用方都不须要考虑请求是否立马处理成功。假设线程池在处理任务的时候由于某些缘由失败了,咱们能够走报警机制(用邮件/短信等渠道去提醒请求方便可)。
不知道你们学过消息队列了没有,咱们经常说消息队列是异步的,不少时候调用方的请求咱们丢到消息队列里边,就告诉调用方咱们这条请求处理成功了。实际上,这个请求可能还交由下游的多个系统去处理,下游的系统可能也是异步的.....
在使用线程池的时候,不少时候咱们也是把他当作异步来使(WebFlux实际上也是将请求丢到线程池嘛),只要咱们的系统之间交互不是强一致性的,又但愿提升系统的吞吐量,咱们就能够考虑使用线程池。
有的时候,咱们须要有一个线程去轮询处理某些任务。
好比,个人系统会有发短信的功能,我调用渠道商的下发接口的后,我须要拿到短信的回执信息,因而我就须要去调用渠道商的回执接口。
此时最简单的作法就是开一个线程,不断的轮询渠道商的回执接口(咱们设定轮询的间隔时间便可)
Thread thread = new Thread(new Runnable() { @Override public void run() { while (true) { try { // 间隔一段时间轮询一次 TimeUnit.MILLISECONDS.sleep(period); // 调用接口 String result = http.post(); // 获得result后进行处理(好比将结果插入到数据库) smsDao.insert(result); } } }); thread.start();
或者有的时候,咱们把任务放到内存阻塞队列或者Redis,也是经过一个线程轮询去取「队列」的数据。
juc其实就是java.util.concurrent
包
咱们在使用线程的时候,或者在平常开发的时候,都是得考虑咱们如今使用的场景是不是线程安全的。
若是不是线程安全的,咱们能够作什么东西来使咱们的程序变得线程安全。
如今已经工做有一段时间了,为何还来写多线程
呢,缘由有如下几个:
read.me
会常常更换。如今的GitHub导航也不合我心意了(太长了),而且早期的文章,说实话排版也不太行,我决定从新搞一波。基于上面的缘由,我决定把个人系列文章汇总成一个PDF/HTML/WORD
文档。说实话,打造这么一个文档花了我很多的时间。为了防止白嫖,关注个人公众号回复「888」便可获取。
PDF的内容很是很是长,干货很是很是的硬,有兴趣的同窗能够浏览一波。共有「129」页
文档的内容均为手打,有任何的不懂均可以直接来问我(公众号有个人联系方式)。
若是你们想要实时关注我更新的文章以及分享的干货的话,微信搜索Java3y。