什么是阻塞
本篇内容主要讲解"什么是阻塞",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"什么是阻塞"吧!
1. 中断就是从中断掉
不是让太监来帮你干活的,他没有那个能力。太监是用来给你调度工作的。
比如,有反叛的军队攻到了城外,太监慌慌张张来报告,你就不得不暂停后宫的活动,提着裤子处理首要的问题;再比如,有刚来的妃子频频抛媚眼,但你还有一大堆公文要批,心有余而力不足。
这种处理问题的方式,就是中断(从中断掉就是太监)。中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的 CPU 暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序。
我们来看下底层的中断处理程序。
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
可以看到,太监只需要给皇帝要做的事情,都编码备案,并固定下处理流程,调整好优先级,皇帝的时间片就可以有效的轮转起来。不至于江山都丢了,还在后宫里风花雪月。
拿网络传输来说,当有了网络数据包,就需要及时处理,否则客户端会超时。这个时候,网卡会立马发出中断请求,CPU就会通过网卡的中断程序去处理这些缓冲区。这都是非常重要的工作。
中断又有硬中断和软中断之分。硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等。软中断是由当前正在运行的进程所产生的,通常优先级比硬中断低一些。
2. 阻塞会占用CPU么?
代入了皇帝这个身份,我们就可以解释一些平常遇到的,令人疑惑的问题。
我们都见过在Concurent包下面,有一个叫做LinkedBlockingQeque的类。从它的名字就可以看出,这是一个阻塞队列。实际上,它也并不是挂着羊头卖狗肉。
如下面的代码,我们通常把它放在循环中。我对while(true)这种东西是有心理阴影的,因为它有可能会跑满你的CPU。
while(true){ Object o = linkedBlockingQeque.poll(); }
但实际上,并不会。因为人家都说了,这是个阻塞队列。
相似的,还有NIO中的select。把逻辑放在while循环里,不怕得报应么?
while (!stop) { int num = selector.select(); if (num == 0) { continue; } Iteratorevents = selector.selectedKeys().iterator(); }
这还真不怕。因为阻塞并不会占用任何资源。
比如,小太监上报了一个折子,是关于吕嫔妃的舅舅的贪污问题处理。但是这个问题,需要等待司法调查的结果,还需要听听爱妃的意见,就先可以把它搁置在一旁。
把问题记录在一个其他的小册子里,等这些依赖的事办的差不多了,同时你又有龙时,那就可以继续处理。
可以看到,这种阻塞性的问题,虽然是个任务,但并不会占用你的任何时间,这在计算机中是一样的。
我们来看一下常见的Java阻塞方式。
sleep和wait
睡和等。用词很巧妙,到底妙在哪呢?因为它是现实中的场景。
sleep
sleep函数会让线程在一定的时间内进入阻塞状态,不能得到cpu时间,但不会释放锁资源。指定的时间一过,线程重新进入可执行状态。
注意我们这里说的是线程,并不是CPU本身。线程不活动了,并不代表CPU不能干其他事情。
比如,今天是接见大臣的黄道吉日,王天师得到了接见的机会,其他的大臣们就得在外面等着被传唤。结果王天师的谈话又臭又长,勾不起你的任何兴趣。正好小太监急匆匆跑来,在你耳边悄悄说:李贵妃生了个儿子!
这是让人振奋的事情,因为其他儿子都在宫斗中被KO了。于是你装模作样的对王天师说:我现在有点头痛,需要小憩一会儿。" 其实你已经偷偷去探望李贵妃了。
注意,这个时候,王天师只能唯唯诺诺的等着。对于"接见"这个主线来说,其他的大臣也只能在外面等着被传唤。它们都没有拿到"接见"这把锁,王天师也一直占用着这把锁,直到你看完了儿子归来。
这就是sleep不释放锁的意思,因为sleep后,在sleep那一瞬间的任何东西都没有改变。
wait
wait( ) 使线程进入阻塞状态,同时释放自己占有的锁资源,和notify( )搭配使用。
对于wait来说,就完全不一样了。
如图,每个监视器(Monitor)在某个时刻,只能被一个线程拥有,该线程就是 "Active Thread"。而其它线程都是 "Waiting Thread",分别在两个队列 " Entry Set"和 "Wait Set"里面等候。在 "Entry Set"中等待的线程状态是 "Waiting for monitor entry",而在 "Wait Set"中等待的线程状态是 "in Object.wait()"。
术语难以理解,还是以皇帝的身份来潇洒一下。
这个时候,你还打算接见大臣。不过,现在不想再one by one了,因为这太低效太枯燥了。某个大臣在你的书房里待得长了些,就有可能有大臣怀疑你在搞gay,这种副作用让人心里不悦。
p2p不行,那就聚在一块谈谈心吧。
正在和你谈话的是王天师,因为这货话比较多,你也比较喜欢他。
王天师说:小太子出生在三伏天,就叫史三伏吧!。
你这才想起自己姓史。作为熟读文章的皇帝,你对此嗤之以鼻,听着这不入流的名字,还隐隐有点生气。
王爱卿,你还是先wait一下吧,听听别人意见。
这个时候,一大堆等着拍马屁的大臣开始举手,跃跃欲试。刘道长抢到了 谈话主线 这把锁。
刘道长: 天地长久,人有终时,北冥有鱼,其名为鲲,可活亿年。我看,就叫史鲲吧。
你听后微微颔首,果然仙人嘴下口水香,但总感觉有点怪异。
注意注意。等着发言的这群大臣,就叫做Entry Set,谁举手举得快,就可以回答这个问题。
像王天师这种被喊停的大臣,就属于Wait Set,只有你重新让他说话,他才有机会。
这整个过程,谈话是可以继续的,并不因为王天师被禁言了谈话就无法进行下去。我们就可以说,wait操作是释放了对象锁的。
计算机中各种所谓的阻塞,都是通过划分不同的队列资源进行处理。比如epoll就是围绕着工作队列和等待队列进行编程的。虽然底层的数据结构有些不同,但思想都是一样的。
线程如何获取时间片?
这个不容易回答,因为你需要知道一个事实:Java中的线程,在Linux上本质是一个轻量级进程,它的调度都是操作系统来完成的。
可以看一下我们最上面那一副让人容易产生密集恐惧症的图片。我们的CPU时间,就划分为多个CPU时间片。你的程序虽然在执行while(true),但不代表它总能够得到CPU资源,所以其他的进程也有机会去执行。
JVM采用抢占式调度模型,指的是让优先级高的线程占用比较多的CPU,如果线程优先级相同,那么就随机选择一个线程,使其占用CPU。
注意"随机"这两个字,就非常的有魔性。它可以让你每天都中100万的彩票,也可能每天喝水都被呛着。
可怜的计算机系统,也参与到大千世界让人无奈的随机命运而来。
但有一种很霸道的任务,对CPU一抢一个准,那就是我们上面提到的硬中断--那些不得不优先处理的事情。
到此,相信大家对"什么是阻塞"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!