首页 > 其他分享 >Heritrix的多线程ToeThread和ToePool

Heritrix的多线程ToeThread和ToePool

时间:2023-09-07 14:37:00浏览次数:37  
标签:toes Heritrix controller 线程 ToePool 多线程 setSize ToeThread


4、Heritrix的多线程ToeThread和ToePool

要想更有效更快捷地抓取网页内容,则必须采用多线程。Heritirx提供了一个标准的线程池ToeThread,用于管理所有的抓取线程。

org.archive.crawler.framework
Class ToePool

java.lang.Object
java.lang.ThreadGroup 
  
      org.archive.crawler.framework.ToePool

如前所述,ToePool的初始化是在CrawlController的初始化方法中完成的。

privatevoidsetupToePool() {       
        toePool = new ToePool(this);       
       //按order.xml中的配置,实例化并启动线程       
        toePool.setSize(order.getMaxToes());       
}       
                       
// ToePool构造函数        
public ToePool(CrawlController c) {         
        super("ToeThreads");         
        this.controller = c;         
        setDaemon(true);         
}

1)真正工作的线程是如何建立的?

从上图可知,其最主要的方法是setSize(int),其源代码如下:

public void setSize(int newsize)         
    {         
        targetSize = newsize;         
        int difference = newsize - getToeCount();         
       //如果发现线程池中的实际线程数量小于应有的数量则启动新的线程        
        if (difference > 0) {         
            // 启动新线程        
            for(int i = 1; i <= difference; i++) {         
                startNewThread();
            }         
        }         
         //如果线程池中的线程数量已经达到需要        
else {         
            // must retire extra threads         
            int retainedToes = targetSize;         
            //将线程池中的线程管理起来放入数组中        
            Thread[] toes = this.getToes();
            //循环去除多余的线程        
            for (int i = 0; i < toes.length ; i++) {         
                if(!(toes[i] instanceof ToeThread)) {         
                    continue;         
                }         
                retainedToes--;         
                if (retainedToes>=0) {         
                    continue; // this toe is spared         
                }         
                // otherwise:         
                ToeThread tt = (ToeThread)toes[i];         
                tt.retire();         
            }         
        }         
}         
 
//用于取得所有属于当前线程池的线程        
private Thread[] getToes()
        Thread[] toes = new Thread[activeCount()+10];         
        /*         
         由于ToePool继承自java.lang.ThreadGroup类,因此当调用enumerate(Thread[] toes)方法时,实际上时将所有该ThreadGroup中开辟的线程放入toes这个数组中,以备后面的管理        
        */         
        this.enumerate(toes);         
        return toes;         
    }         
 
//开启一个线程        
private synchronized void startNewThread() {         
        ToeThread newThread = new ToeThread(this, nextSerialNumber++);         
        newThread.setPriority(DEFAULT_TOE_PRIORITY);         
        newThread.start();         
    }

从上面的代码可知:线程池本身在创建的时候,并没有任何活动的线程实例,只有当它的setSize方法被调用时,才有可能创建新线程;如果当setSize方法被调用多次而传入不同的参数时,线程池会根据参数里所设定的值的大小,来决定池中所管理的线程数量的增减。

2)一个ToeThread到底是如何处理从Frontier中获得的链接?

当线程被启动后,执行的是其run()方法中的片段。

public void run() {         
        String name = controller.getOrder().getCrawlOrderName();         
        logger.fine(getName()+" started for order '"+name+"'");         
 
        try {         
            while ( true ) {         
                // 检查是否应该继续处理        
                continueCheck();         
                
                setStep(STEP_ABOUT_TO_GET_URI);         
                
                //使用Frontier的next方法从Frontier中取出下一个要处理的链接        
                CrawlURI curi = controller.getFrontier().next();         
                
                //同步当前线程        
                synchronized(this) {         
                    continueCheck();         
                    setCurrentCuri(curi);         
                }         
                
                //处理取出的链接        
                processCrawlUri();
                
                setStep(STEP_ABOUT_TO_RETURN_URI);         
     
                //检查是否应该继续处理        
                continueCheck();         
 
                /*         
                使用Frontier的finished方法来对刚才处理的链接做收尾工作,比如将分析得到的新的链接加入到等级队列中去        
                */         
                synchronized(this) {         
                    controller.getFrontier().finished(currentCuri);         
                    setCurrentCuri(null);         
                }         
                
                //后续的处理        
                setStep(STEP_FINISHING_PROCESS);         
                lastFinishTime = System.currentTimeMillis();         
       
                //释放链接        
                controller.releaseContinuePermission();         
                if(shouldRetire) {         
                    break; // from while(true)         
                }         
            }         
        } catch (EndedException e) {         
            // crawl ended (or thread was retired), so allow thread to end         
        } catch (Exception e) {         
            // everything else (including interruption)         
            logger.log(Level.SEVERE,"Fatal exception in "+getName(),e);         
        } catch (OutOfMemoryError err) {         
            seriousError(err);         
        } finally {         
            controller.releaseContinuePermission();         
        }         
        setCurrentCuri(null);         
        //清理缓存数据        
        this.httpRecorder.closeRecorders();         
        this.httpRecorder = null;         
        localProcessors = null;         
 
        logger.fine(getName()+" finished for order '"+name+"'");         
        setStep(STEP_FINISHED);         
        controller.toeEnded();         
        controller = null;         
    }

 

标签:toes,Heritrix,controller,线程,ToePool,多线程,setSize,ToeThread
From: https://blog.51cto.com/u_2544485/7396867

相关文章

  • Heritrix架构学习笔记(三)
    3、Frontier链接制造工厂在heritrix-1.12.1/docs/articles/developer_manual/frontier.html下可找到Heritrix的官方文档的一个Frontier例子:/***AsimpleFrontierimplementationfortutorialpurposes*/publicclassMyFront......
  • Heritrix架构学习笔记(一)
    1、抓取起点CrawlOrder在heritrix-1.12.1/docs/apidocs目录下可以查看其API:org.archive.crawler.datamodelClassCrawlOrderjava.lang.Objectjavax.management.Attributeorg.archive.crawler.settings.Typeorg.archive.crawler.settings.Complex......
  • heritrix配置篇
    目前对Heritrix做了初步选型测试,有了一些总结:1.关于安装:     目前的版本号为1.12.1,官网地址为 http://crawler.archive.org/。常规安装,即解压到相关目录,之后配置系统环境变量"HERITRIX_HOME"到该解压目录(Java环境已经配置好)。2.安装的后续工作:     将%HERIT......
  • 杰哥教你面试之一百问系列:java中高级多线程concurrent的使用
    目录问题1:什么是ConcurrentHashMap?它与HashMap的区别是什么?问题2:什么是CopyOnWriteArrayList?它适用于什么样的场景?问题3:什么是BlockingQueue?它的作用是什么?举例说明一个使用场景。问题4:什么是Semaphore?它如何控制并发访问?问题5:什么是CountDownLatch?它适用于什么场景?问题6:什么是Cyc......
  • java多线程几个方法的基本概念
    一、run()和start()这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用run()方法,这是由Java的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.二、关键字Synchronized这个关键字用于保护共享数据,当然......
  • 关于多线程的相关概念
    多线程多线程的好处多线程可以提高CPU的使用效率比如单线程运行时遇到网络等待的耗时操作时,只能乖乖的等待,且交互终端但是多线程的情况下,一个线程负责交互,另一个负责计算线程的访问权限知道哪些数据是线程私有,哪些变量是线程之间共享数据线程调度和优先级当线程数量......
  • Windows驱动程序是支持多线程【chatgpt】
    是的,Windows驱动程序是支持多线程的。驱动程序是运行在操作系统内核空间的软件模块,可以通过创建和管理多个线程来实现并发处理的能力。通过多线程,驱动程序可以同时处理多个请求或事件,提高系统的响应性能和并发处理能力。在Windows驱动程序的开发中,可以使用内核模式线程来执行异步......
  • Linux应用编程_多线程编程
    (1)线程的创建: pthread_ttid=pthread_self(); //获取当前线程的tid号 intret=pthread_create(&tid1,NULL,fun1,(void*)&a);//创建线程传入变量a的地址 ret=pthread_create(&tid2,NULL,fun2,(void*)(long)a);//创建线程传入变量a的值(2)线程的退出与回收: pth......
  • 多线程中的不同区域的变量的安全性问题测试
    如果是方法中的变量,不存在线程安全问题。方法中的变量代码片段:publicclassHasSelfPrivateNum{publicvoidaddI(StringuserName){ //这里的num变量是存在于addI这个方法里面的intnum=0;try{if(userName.equals("a")){......
  • 《C++》11新特性--多线程
    thread创建线程,不会阻塞主线程thread成员函数voidthread::join();阻塞线程,当前线程执行完毕才会往下执行boolthread::joinble();线程是否可以连接,返回voidthread::detach();分离主线程和子线程的关联voidprintI(){for(size_ti=0;i<100;i++){std::c......