Spider剩下的CountableThreadPool

在上一篇的Spider中我们一定注意到了threadpool这个变量,这个变量是Spider中的线程池,具体代码

public class CountableThreadPool {

private int threadNum;

private AtomicInteger threadAlive = new AtomicInteger();

private ReentrantLock reentrantLock = new ReentrantLock();

private Condition condition = reentrantLock.newCondition();

public CountableThreadPool(int threadNum) {
this.threadNum = threadNum;
this.executorService = Executors.newFixedThreadPool(threadNum);
}

public CountableThreadPool(int threadNum, ExecutorService executorService) {
this.threadNum = threadNum;
this.executorService = executorService;
}

public void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}

public int getThreadAlive() {
return threadAlive.get();
}

public int getThreadNum() {
return threadNum;
}

private ExecutorService executorService;

public void execute(final Runnable runnable) {

if (threadAlive.get() >= threadNum) {
try {
reentrantLock.lock();
while (threadAlive.get() >= threadNum) {
try {
condition.await();
} catch (InterruptedException e) {
}
}
} finally {
reentrantLock.unlock();
}
}
threadAlive.incrementAndGet();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
runnable.run();
} finally {
try {
reentrantLock.lock();
threadAlive.decrementAndGet();
condition.signal();
} finally {
reentrantLock.unlock();
}
}
}
});
}

public boolean isShutdown() {
return executorService.isShutdown();
}

public void shutdown() {
executorService.shutdown();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
CountableThreadPool提供了设置Executor或者默认创建的方式,如果不是很懂Java的线程池先去补习一下~最主要的三个变量

private AtomicInteger threadAlive = new AtomicInteger();

private ReentrantLock reentrantLock = new ReentrantLock();

private Condition condition = reentrantLock.newCondition();
1
2
3
4
5
1
2
3
4
5
threadAlive表示目前正在执行的线程,reentrantLock是一个自旋锁,用于对条件变量操作的同步,condition用户唤醒阻塞线程的条件变量。

关键的方法:

public void execute(final Runnable runnable) {

if (threadAlive.get() >= threadNum) {
try {
reentrantLock.lock();
while (threadAlive.get() >= threadNum) {
try {
condition.await();
} catch (InterruptedException e) {
}
}
} finally {
reentrantLock.unlock();
}
}
threadAlive.incrementAndGet();
executorService.execute(new Runnable() {
@Override
public void run() {
try {
runnable.run();
} finally {
try {
reentrantLock.lock();
threadAlive.decrementAndGet();
condition.signal();
} finally {
reentrantLock.unlock();
}
}
}
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
使用threadAlive这个变量来控制目前的活动线程,如果超出定义的线程数就阻塞,为什么这样呢,因为我们创建的是固定大小的线程池,默认的newFixedThreadPool创建的最大线程数就是传入的参数,如果线程数量超过线程池中的数值,对于默认的操作就是抛异常了。可以看一下这篇博客:
http://uule.iteye.com/blog/1123185
http://blog.csdn.net/sd0902/article/details/8395677

Spider剩下的SpiderMonitor

先说一句

SpiderMonitor是负责监控Spider的运行状态的,建议仔细阅读官方文档
http://webmagic.io/docs/zh/posts/ch4-basic-page-processor/monitor.html
http://my.oschina.net/xpbug/blog/221547
所以如果这部分对你没什么用,你可以跳过去,我就没用到~

开始吧

在Spider的代码中我们看到了这个

public void run() {
try {
processRequest(requestFinal);
onSuccess(requestFinal);
} catch (Exception e) {
onError(requestFinal);
logger.error("process request " + requestFinal + " error", e);
} finally {
pageCount.incrementAndGet();
signalNewUrl();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
对于onSuccess(requestFinal)和onError(requestFinal)这个方法名,如果你看的多了一眼就知道这是个接口,那么回调在哪里?也就是SpiderMonitor的内部类

public class SpiderMonitor {

private static SpiderMonitor INSTANCE = new SpiderMonitor();

private AtomicBoolean started = new AtomicBoolean(false);

private Logger logger = LoggerFactory.getLogger(getClass());

private MBeanServer mbeanServer;

private String jmxServerName;

private List<SpiderStatusMXBean> spiderStatuses = new ArrayList<SpiderStatusMXBean>();

protected SpiderMonitor() {
jmxServerName = "WebMagic";
mbeanServer = ManagementFactory.getPlatformMBeanServer();
}

/**
* Register spider for monitor.
*
* @param spiders spiders
* @return this
*/
public synchronized SpiderMonitor register(Spider... spiders) throws JMException {
for (Spider spider : spiders) {
MonitorSpiderListener monitorSpiderListener = new MonitorSpiderListener();
if (spider.getSpiderListeners() == null) {
List<SpiderListener> spiderListeners = new ArrayList<SpiderListener>();
spiderListeners.add(monitorSpiderListener);
spider.setSpiderListeners(spiderListeners);
} else {
spider.getSpiderListeners().add(monitorSpiderListener);
}
SpiderStatusMXBean spiderStatusMBean = getSpiderStatusMBean(spider, monitorSpiderListener);
registerMBean(spiderStatusMBean);
spiderStatuses.add(spiderStatusMBean);
}
return this;
}

protected SpiderStatusMXBean getSpiderStatusMBean(Spider spider, MonitorSpiderListener monitorSpiderListener) {
return new SpiderStatus(spider, monitorSpiderListener);
}

public static SpiderMonitor instance() {
return INSTANCE;
}

public class MonitorSpiderListener implements SpiderListener {

private final AtomicInteger successCount = new AtomicInteger(0);

private final AtomicInteger errorCount = new AtomicInteger(0);

private List<String> errorUrls = Collections.synchronizedList(new ArrayList<String>());

@Override
public void onSuccess(Request request) {
successCount.incrementAndGet();
}

@Override
public void onError(Request request) {
errorUrls.add(request.getUrl());
errorCount.incrementAndGet();
}

public AtomicInteger getSuccessCount() {
return successCount;
}

public AtomicInteger getErrorCount() {
return errorCount;
}

public List<String> getErrorUrls() {
return errorUrls;
}
}

protected void registerMBean(SpiderStatusMXBean spiderStatus) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
ObjectName objName = new ObjectName(jmxServerName + ":name=" + spiderStatus.getName());
mbeanServer.registerMBean(spiderStatus, objName);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
我们看到了在onSuccess和onError做了一些记录,主要是为了监控,如果你希望在爬虫成功或者失败实现一些自己方法也可以实现这个接口

public interface SpiderListener {

public void onSuccess(Request request);

public void onError(Request request);
}
1
2
3
4
5
6
1
2
3
4
5
6
如果你对于Java的接口回调不是很懂那么推荐你看看《Head First设计模式》第一章,策略模式。

写在后面

这篇博客还是很简单的,主要完善了Spider的细小模块,后面将会介绍Spider的四大组件,如果喜欢多多支持~

CountableThreadPool的更多相关文章

  1. 【转】WebMagic-总体流程源码分析

    转自:http://m.blog.csdn.net/article/details?id=51943601 写在前面 前一段时间开发[知了]用到了很多技术(可以看我前面的博文http://blog.c ...

  2. HttpClient 专题

    HttpClient is a HTTP/1.1 compliant HTTP agent implementation based on HttpCore. It also provides reu ...

  3. Java 多线程爬虫及分布式爬虫架构探索

    这是 Java 爬虫系列博文的第五篇,在上一篇 Java 爬虫服务器被屏蔽,不要慌,咱们换一台服务器 中,我们简单的聊反爬虫策略和反反爬虫方法,主要针对的是 IP 被封及其对应办法.前面几篇文章我们把 ...

  4. Java 多线程爬虫及分布式爬虫架构

    这是 Java 爬虫系列博文的第五篇,在上一篇 Java 爬虫服务器被屏蔽,不要慌,咱们换一台服务器 中,我们简单的聊反爬虫策略和反反爬虫方法,主要针对的是 IP 被封及其对应办法.前面几篇文章我们把 ...

  5. webmagic源码浅析

    webmagic简介 webmagic可以说是中国传播度最广的Java爬虫框架,https://github.com/code4craft/webmagic,阅读相关源码,获益良多.阅读作者博客[代码 ...

随机推荐

  1. Oracle企业管理框架

    oracle管理服务器 是一个基于java的web构件,该构件是dba用来监视和控制oracle企业框架内各个受管理目标的实际界面 oracle储存库 已收集到并与受管理目标有关的配置和监视信息被存储 ...

  2. DOM修改元素的方法总结

    今天我们要谈谈DOM元素的修改(包括修改内容,属性,样式).修改内容的方法----3种:elem.innerHTML:获取或设置元素开始标签到结束标签之间的原始HTML代码片段:elem.textCo ...

  3. 编程语言分类及python所属类型

    编程语言分类及python所属类型 编程语言主要从以下几个角度为进行分类:编译型和解释型.静态语言和动态语言.强类型定义语言和弱类型定义语言. 编译和解释的区别是什么? 编译器是把源程序的每一条语句都 ...

  4. 大数据技术之HBase

    第1章 HBase简介 1.1 什么是HBase HBase的原型是Google的BigTable论文,受到了该论文思想的启发,目前作为Hadoop的子项目来开发维护,用于支持结构化的数据存储. 官方 ...

  5. 微服务开源生态报告 No.5

    「微服务开源生态报告」,汇集各个开源项目近期的社区动态,帮助开发者们更高效的了解到各开源项目的最新进展. 社区动态包括,但不限于:版本发布.人员动态.项目动态和规划.培训和活动. 非常欢迎国内其他微服 ...

  6. MongoDB负载信息一目了然 阿里云HDM重磅发布MongoDB监控和诊断功能

    混合云数据库管理(HDM)的统一监控.告警.诊断功能新增了对MongoDB的支持. 通过直观的方式将MongoDB多个维度的负载信息统一整合,不仅可以清晰的查看实时负载信息,也可以方便的确认历史负载情 ...

  7. NLP+2vec︱认识多种多样的2vec向量化模型

    1.word2vec 耳熟能详的NLP向量化模型. Paper: https://papers.nips.cc/paper/5021-distributed-representations-of-wo ...

  8. springboot thymeleaf【转】【补】

    thymeleaf模板 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html 1.引入thymeleaf依赖 <!-- ...

  9. Directx11学习笔记【八】 龙书D3DApp的实现

    原文:Directx11学习笔记[八] 龙书D3DApp的实现 directx11龙书中的初始化程序D3DApp跟我们上次写的初始化程序大体一致,只是包含了计时器的内容,而且使用了深度模板缓冲. D3 ...

  10. icheck的使用

    一.什么是icheck 就是用来美化单选框.复选框的. 二.如何使用 1.下载 到 github 下载.https://github.com/fronteed/icheck 下载完毕.解压.目录结构如 ...