最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JAVA 多線程爬蟲實例詳解

 更新時間:2017年04月25日 11:15:48   投稿:lqh  
這篇文章主要介紹了JAVA 多線程爬蟲實例詳解的相關(guān)資料,需要的朋友可以參考下

JAVA 多線程爬蟲實例詳解

前言

以前喜歡Python的爬蟲是出于他的簡潔,但到了后期需要更快,更大規(guī)模的爬蟲的時候,我才漸漸意識到Java的強大。Java有一個很好的機制,就是多線程。而且Java的代碼效率執(zhí)行起來要比python快很多。這份博客主要用于記錄我對多線程爬蟲的實踐理解。

線程

線程是指一個任務從頭至尾的執(zhí)行流。線程提供了運行一個任務的機制。對于Java而言,可以在一個程序中并發(fā)地啟動多個線程。這些線程可以在多處理器系統(tǒng)上同時運行。

runnable接口

任務類必須實現(xiàn)runnable接口,它只包含一個run方法。需要實現(xiàn)這個方法來告訴系統(tǒng)線程將如何運行。

Thread類

包含為任務而創(chuàng)建的線程的構(gòu)造方法,以及控制線程的方法。

synchronized關(guān)鍵字

為避免競爭狀態(tài),防止多個線程同時進入程序的某個特定部分,即臨界區(qū),以便一次只有一個線程可以訪問臨界區(qū)。

利用加鎖同步

Java可以顯式加鎖,一個鎖是一個Lock接口的實例,它定義了加鎖和釋放鎖的方法。

線程池

線程池是管理開發(fā)執(zhí)行任務個數(shù)的理想方法。Java提供Executor接口來執(zhí)行線程池中的任務,提供ExecutorService接口管理和控制任務。

使用線程池的方法獲取url列表

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
 * 獲取京東評論url列表
 */

public class MyThreading {
  private static String p_id = null;
  private static Url urls = null;

  public MyThreading(String p_id){
    this.p_id = p_id ;   // 京東商品的id
    urls = new Url(p_id); 
  }

  public List<String> getUriList(){
    ExecutorService executor = Executors.newCachedThreadPool();
    for (int i = 0 ; i < 600 ; i ++){
      executor.execute(new AddUrl(i));    // 添加任務到線程池
    }
    executor.shutdown();
    while (!executor.isTerminated()){}
    return urls.getList();
  }

  public static class AddUrl implements Runnable{
    int page;
    public AddUrl(int page){
      this.page = page;
    }
    public void run(){
      urls.addList(page);   // 啟動多線程任務
    }
  }

  public static class Url {

    private static Lock lock = new ReentrantLock();     // 開啟顯式家鎖
    private static List<String> urlList = new ArrayList();     
    private String p_id;

    public Url(String p_id ){
      this.p_id = p_id ;
    }
    public List<String> getList(){
      return urlList;
    }
    public void addList(int page){
      lock.lock();
      try{
        String url = "http://club.jd.com/productpage/p-" + p_id + "-s-0-t-0-p-" + String.valueOf(page) + ".html";
//       Thread.sleep(5);
        urlList.add(url);    //添加url到url列表
      }catch(Exception ex ){
      }
      finally {
        lock.unlock();     // 解鎖
      }

    }
  }
  public static void main(String[] args) {
    String p_id = "2441288";
    MyThreading myThreading = new MyThreading(p_id);
    List <String> urlList = myThreading.getUriList();
    for(String url : urlList){
      System.out.println(url);
    }
    System.out.println(urlList.size());
  }
}

代碼分析

  • 代碼的作用:獲取京東評論的url列表
  • 類的說明:MyThreading是主類, AddUrl和Url是它的內(nèi)部類,AddUrl實現(xiàn)了runnable的接口,主要啟動多線程服務運行Url的addList方法。而Url是最內(nèi)核的部分 ,他提供addList任務和多線程的共享區(qū)域urlList,所以在實現(xiàn)添加url的步驟中,需要對urlList加鎖。
  • 線程池主要有兩種類型,一個是固定線程池,即newFixedThreadPool;另一個是newCachedThreadPool,這個主要利用了緩沖機制,能動態(tài)地添加線程。在上述代碼中,我主要使用了newCachedthreadPool.

使用線程池的方法根據(jù)url列表爬取網(wǎng)頁元素

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class ThreadingCrawel {
  private static Content content = null;
  private static List<String> urlList = null;

  public ThreadingCrawel(List<String> urlList){
    this.urlList = urlList;
    content = new Content();
  }
  public List<String> getContent(){

    ExecutorService executor = Executors.newCachedThreadPool();
    for (String url : urlList){
      executor.execute(new AddContent(url));
    }
    executor.shutdown();
    while(!executor.isTerminated()){}
    return content.getContent();

  }

  public static class AddContent implements Runnable{
    String url;
    public AddContent(String url){
      this.url = url;
    }
    public void run(){
      content.addContent(url);
    }
  }

  public static class Content {

    private static Lock lock = new ReentrantLock();
    private static List<String> contentList = new ArrayList();

    public void addContent(String url){

      String content = "";
      BufferedReader in = null;
      try{
        URL realUrl = new URL(url);
        URLConnection connection = realUrl.openConnection();
        in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "gbk"));
        String line;
        while( (line = in.readLine()) != null){
          content += line +"\n";
        }
      }catch(Exception e){
        e.printStackTrace();
      }
      finally{
        try{
          if (in != null){
            in.close();
          }
        }catch(Exception e2){
          e2.printStackTrace();
        }
      }

      Pattern p = Pattern.compile("content\":\".*?\"");
      Matcher match = p.matcher(content);
      String tmp;
       lock.lock();
      while(match.find()){
        tmp = match.group();
        tmp = tmp.replaceAll("\"", "");
        tmp = tmp.replace("content:", "");
        tmp = tmp.replaceAll("<.*?>", "");
        contentList.add(tmp);
        try {
          Thread.sleep(1);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
      lock.unlock();

    }
    public List getContent(){
      return contentList;
    }
  }
  public static void main(String[] args){
    long start = System.currentTimeMillis();
    String p_id = "2441288";
    MyThreading myThreading = new MyThreading(p_id);
    List <String> urlList = myThreading.getUriList();
    ThreadingCrawel threadingCrawel = new ThreadingCrawel(urlList);
    List <String> contentList = threadingCrawel.getContent();
    for(String content : contentList){
      System.out.println(content);
    }
    long end = System.currentTimeMillis();
    System.out.println(end - start);
  }
}

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • SpringCloud Netflix Ribbon超詳細講解

    SpringCloud Netflix Ribbon超詳細講解

    這篇文章主要介紹了SpringCloud筆記HoxtonNetflix之Ribbon負載均衡,Ribbon是管理HTTP和TCP服務客戶端的負載均衡器,Ribbon具有一系列帶有名稱的客戶端(Named Client),對SpringCloud Ribbon負載均衡相關(guān)知識感興趣的朋友一起看看吧
    2022-10-10
  • Java自動讀取指定文件夾下所有文件的方法

    Java自動讀取指定文件夾下所有文件的方法

    這篇文章主要為大家詳細介紹了Java自動讀取指定文件夾下所有文件的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02
  • Java實現(xiàn)屏幕截圖工具的代碼分享

    Java實現(xiàn)屏幕截圖工具的代碼分享

    這篇文章主要為大家介紹了如何利用Java語言編寫一個電腦屏幕截圖工具,文中的示例代碼講解詳細,對我們學習有一定的幫助,需要的可以參考一下
    2022-05-05
  • 使用java8的方法引用替換硬編碼的示例代碼

    使用java8的方法引用替換硬編碼的示例代碼

    這篇文章主要介紹了使用java8的方法引用替換硬編碼,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot項目部署到服務器的兩種方式

    SpringBoot項目部署到服務器的兩種方式

    目前,前后端分離的架構(gòu)已成主流,而使用SpringBoot構(gòu)建Web應用是非??焖俚?項目發(fā)布到服務器上的時候,只需要打成一個jar包,然后通過命令 : java -jar jar包名稱即可啟動服務了,本文介紹了SpringBoot項目部署到服務器的兩種方式,需要的朋友可以參考下
    2024-10-10
  • spring boot 配置動態(tài)刷新實現(xiàn)詳解

    spring boot 配置動態(tài)刷新實現(xiàn)詳解

    這篇文章主要介紹了spring boot 配置動態(tài)刷新實現(xiàn)詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • java WSDL接口webService實現(xiàn)方式

    java WSDL接口webService實現(xiàn)方式

    這篇文章主要為大家詳細介紹了java WSDL接口webService實現(xiàn)方式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Json在Struts中的轉(zhuǎn)換與傳遞方法

    Json在Struts中的轉(zhuǎn)換與傳遞方法

    下面小編就為大家?guī)硪黄狫son在Struts中的轉(zhuǎn)換與傳遞方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • Java利用httpclient通過get、post方式調(diào)用https接口的方法

    Java利用httpclient通過get、post方式調(diào)用https接口的方法

    這篇文章主要介紹了Java利用httpclient通過get、post方式調(diào)用https接口的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Java中關(guān)鍵字final finally finalize的區(qū)別介紹

    Java中關(guān)鍵字final finally finalize的區(qū)別介紹

    這篇文章主要給大家分享的是 Java中final,finally,finalize 到底有什么區(qū)別,文章圍繞final,finally,finalize的相關(guān)資料展開詳細內(nèi)容,具有一定的參考的價值,需要的朋友可以參考一下
    2022-04-04

最新評論

乌兰浩特市| 南京市| 古田县| 嘉义县| 凤台县| 郧西县| 油尖旺区| 伊川县| 青龙| 新源县| 海兴县| 高淳县| 行唐县| 沾益县| 宁阳县| 罗山县| 垫江县| 南华县| 赤城县| 平山县| 永平县| 余江县| 顺义区| 华亭县| 永胜县| 嘉禾县| 定日县| 屏南县| 余江县| 克拉玛依市| 水城县| 波密县| 九江市| 石城县| 营口市| 永平县| 巴彦县| 夏津县| 长乐市| 安庆市| 高密市|