博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
当Scheduler拿不到url的 时候,不能立即退出
阅读量:6704 次
发布时间:2019-06-25

本文共 1877 字,大约阅读时间需要 6 分钟。

在webmagic的多线程抓取中有一个比较麻烦的问题:当Scheduler拿不到url的 时候,不能立即退出,需要等到没抓完的线程都运行完毕,没有新url产生时,才能退出。之前使用Thread.sleep来实现,当拿不到url 时,sleep一段时间再取,确定没有线程执行之后,再退出。

但是这种方式始终不够优雅。Java里面有wait/notify机制可以解决这种同步的问题。于是webmagic 0.4.0用wait/notify机制代替了之前的Thread.sleep机制。代码如下:

while (!Thread.currentThread().isInterrupted() && stat.get() == STAT_RUNNING) {        Request request = scheduler.poll(this);        if (request == null) {            if (threadAlive.get() == 0 && exitWhenComplete) { break; } // wait until new url added waitNewUrl(); } else { final Request requestFinal = request; threadAlive.incrementAndGet(); executorService.execute(new Runnable() { @Override public void run() { try { processRequest(requestFinal); } catch (Exception e) { logger.error("download " + requestFinal + " error", e); } finally { threadAlive.decrementAndGet(); signalNewUrl(); } } }); } } private void waitNewUrl() { try { newUrlLock.lock(); try { newUrlCondition.await(); } catch (InterruptedException e) { } } finally { newUrlLock.unlock(); } }

这里当线程完成之后,会调用signalNewUrl()来通知主线程,停止等待!

0.4.0发布之后,有用户问我,为什么有的时候抓完无法退出?我开始就怀疑这里可能存在线程安全问题,但是苦于无法复现。

思考了一下,有可能存在这样执行情况:

  1. threadAlive>0,执行if (threadAlive.get() == 0 && exitWhenComplete)check跳过,于是准备进入waitNewUrl();
  2. 此时最后一个子线程执行结束,threadAlive.decrementAndGet();signalNewUrl();相继执行;
  3. 此时主线程进入waitNewUrl(),结果已无线程执行,也无人可以notify它了,于是线程一直等待…

那么似乎在lock里加入double-check就OK了?但是今天看了这篇文章,大概意思是:出了问题不要靠猜!一定要复现并测试!

于是决定手动模拟!开启10个线程,并mock了所有部件,循环10000次去执行,代码不贴了,地址:。执行一下,果然到了第13次就卡住了!jstack之后,果然卡在newUrlCondition.await();这里!

然后加入double-check:

private void waitNewUrl() { try { newUrlLock.lock(); //double check if (threadAlive.get() == 0 && exitWhenComplete) { return; } try { newUrlCondition.await(); } catch (InterruptedException e) { } } finally { newUrlLock.unlock(); } }

结果执行成功!至此问题解决!

经过这个例子,也大致明白了为什么wait/notify之前总是要先lock。为什么呢?有机会写一篇文章总结一下吧!

很简单,是吧?其实这篇文章只想说明一件事:出了bug不要靠猜!一定要复现并确认解决!

转载地址:http://ovgoo.baihongyu.com/

你可能感兴趣的文章
Java操作MongoDB
查看>>
分布式系统开发工具包 —— 基于Kryo的Java对象序列化
查看>>
nagios监控服务器的搭建
查看>>
Sql server优化50法
查看>>
使用Server 2008新GPO做驱动器映射
查看>>
Java网络编程从入门到精通(5):使用InetAddress类的getHostName方法获得域名
查看>>
Lync Server外部访问系列PART5:模拟公网DNS
查看>>
运维自动化之使用PHP+MYSQL+SHELL打造私有监控系统(一)
查看>>
总结面试时没有回答上的内存对齐问题
查看>>
Node.js 使用jQuery取得Nodejs http服务端返回的JSON对象示例
查看>>
【原】iOS:手把手教你发布代码到CocoaPods(Trunk方式)
查看>>
使用Cross-Page Postback(跨页面提交)在页面间传递数据
查看>>
To install 64-bit ODBC drivers
查看>>
[20150629]12c物化视图刷新Out of place
查看>>
Linux下编译安装Apache httpd 2.4
查看>>
IOS7.1.1真的像网上流传的那么好?没有任何问题么??
查看>>
剖析Docker Swarm和Mesos:是什么?如何结合?有什么优势?
查看>>
OpenSceneGraph in ActiveX by ActiveQt
查看>>
MPLS服务合同到期了,是否该续签?
查看>>
机器学习自主解决安全威胁离我们还有多远?
查看>>