爬虫(二)

思维导图

Java爬取京东商品数据

线程

1. 实现方式

  • 继承Thread类
  • 实现Runnable接口
  • 通过callable和future 实现有返回值的线程
public static void main(String[] args) throws Exception {
    //Callable的返回值就要使用Future对象,Callable负责计算结果,Future负责拿到结果
    //1、实现Callable接口
    Callable<Integer> callable = new Callable<Integer>() {
        public Integer call() throws Exception {
            int i=999;     
            return i;
        }
    };
    //2、使用FutureTask启动线程
    //FutureTask是Runnable的子类RunnableFuture的实现类
    FutureTask<Integer> future = new FutureTask<Integer>(callable);
    new Thread(future).start();
    //3、获取线程的结果
    System.out.println(future.get());
  
}

2. 线程池

在java中提供了Executors类, 用来创建线程池, 大体分为如下几类:

    1. 创建一个固定大小的线程池
    • 使用场景: 线程的内容比较稳定
    • 使用多个线程来并发执行提交的任务。底层是个无界队列
static ExecutorService newFixedThreadPool(int nThreads);
    1. 创建一个可缓存的线程池(可大可小)
    • 使用场景: 线程的任务会发生改变
    • 创建非固定数量,可缓存的线程池。当提交的任务数量起起伏伏时,会自动创建或者减少执行线程的数量。
static ExecutorService newCachedThreadPool()  
    1. 创建一个定时执行的线程池
    • 使用场景: 需要进行定时执行的时候
    • scheduleAtFixedRate()
    • scheduleWithFixedDelay()
    • 区别:
      • scheduleAtFixedRate 固定周期执行, 不管上次的线程执行完成没有
      • scheduleWithFixedDelay 固定周期执行, 此方法会等待上次线程执行完成后按照周期执行
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)  
    
    //每秒钟会调用MyRunnable任务, 不管这个MyRunnable有没有执行完成, 都是每秒执行
    executorService.scheduleAtFixedRate(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);

 //每秒钟会调用MyRunnable任务, 当执行下一次任务, 会先看上一次的任务有没有执行完成, 如果没有, 先等待, 当上一次的任务执行完成以后, 会等待1秒的时候, 执行下一次请求
    executorService.scheduleWithFixedDelay(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);

    1. 创建一个单线程执行的线程池
//创建单线程,在任务执行时,会依次执行任务。底层是个无界队列。
static ExecutorService newSingleThreadExecutor()  
    1. 创建一个单线程定时执行的线程池
static ScheduledExecutorService newSingleThreadScheduledExecutor() 
    
    //scheduleAtFixedRate 固定周期执行完毕
    //这个也是一个定时执行的线程池, 但是这个线程池中只有一个线程, 如果使用这个方法的话, 那么如果上一个线程没有执行完成, 会直接干掉这个任务, 重新执行任务
    executorService.scheduleAtFixedRate(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);
    //scheduleWithFixedDelay 上一次执行完毕之后下一次开始执行
    executorService.scheduleWithFixedDelay(new MyRunnable(),0,1000,TimeUnit.MILLISECONDS);

队列

1. 原生队列

在java中提供了一个类, queue用来模拟普通原生队列的

  • 普通队列的特性:
      1. 先进先出
      1. 队列的头部保存的应该是在队列中存储时间最长的, 队尾应该是存储时间最短的
    • 3)新的元素应该插入的队列的尾部, 取出的元素应该是队列的头部
      1. 队列一般不允许随机访问其中的某个元素
  • 常用方法:
抛出异常返回特殊值
插入add(e)offer(e)
移除remove()poll()
检查element()peek()
  • 插入: add(元素) offer(元素);
    • 建议使用offer方法, 一般来说会比add方法更高效
  • 移除: remove() poll();
    • 建议使用poll进行移除
  • 检查: element() peek()
    • 检查操作其实就是到队列的头部获取一个内容, 但是不删除
    • 建议使用peek() 当获取不到的时候null

2. 双端队列

在java中, 使用Deque双端队列, 顾名思义, 可以分别在队列的两边进行插入和移除数据

  • 常用方法
第一个元素(头部)最后一个元素(尾部)
抛出异常特殊值抛出异常特殊值
插入addFirst(e)offerFirst(e)addLast(e)offerLast(e)
移除removeFirst()pollFirst()removeLast()pollLast()
检查getFirst()peekFirst()getLast()peekLast()
  • 一般来说, 我们通常使用的都是返回特殊值的方法

3. 阻塞队列—线程安全

  • BlockingQueue
    • 阻塞的原生队列
抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)[offer(e, time, unit)](…/…/…/java/util/concurrent/BlockingQueue.html#offer(E, long, java.util.concurrent.TimeUnit))
移除remove()[poll()](…/…/…/java/util/concurrent/BlockingQueue.html#poll(long, java.util.concurrent.TimeUnit))take()[poll(time, unit)](…/…/…/java/util/concurrent/BlockingQueue.html#poll(long, java.util.concurrent.TimeUnit))
检查element()peek()不可用不可用
  • BlockingDeque
    • 阻塞的双端队列
第一个元素(头部)
抛出异常特殊值阻塞超时期
插入addFirst(e)offerFirst(e)putFirst(e)[offerFirst(e, time, unit)](…/…/…/java/util/concurrent/BlockingDeque.html#offerFirst(E, long, java.util.concurrent.TimeUnit))
移除removeFirst()[pollFirst()](…/…/…/java/util/concurrent/BlockingDeque.html#pollFirst(long, java.util.concurrent.TimeUnit))takeFirst()[pollFirst(time, unit)](…/…/…/java/util/concurrent/BlockingDeque.html#pollFirst(long, java.util.concurrent.TimeUnit))
检查getFirst()peekFirst()不适用不适用
最后一个元素(尾部)
抛出异常特殊值阻塞超时期
插入addLast(e)offerLast(e)putLast(e)[offerLast(e, time, unit)](…/…/…/java/util/concurrent/BlockingDeque.html#offerLast(E, long, java.util.concurrent.TimeUnit))
移除removeLast()pollLast()takeLast()[pollLast(time, unit)](…/…/…/java/util/concurrent/BlockingDeque.html#pollLast(long, java.util.concurrent.TimeUnit))
检查getLast()peekLast()不适用不适用

阻塞的方法:

  • put(e);
    • put方法, 如果队列容量满了, 那么此方法会进行永久等待
  • take();
    • take方法, 如果队列当中没有了元素, 那么此方法会进行永久等待

超时的方法:

  • offer(e,time,unit);
    • 带时间参数的offer方法, 如果队列容量满了, 那么此方法会在规定的时间内进行等待
  • poll(time,unit);
    • 带时间参数的poll方法, 如果队列没有了元素, 那么此方法会 规定时间内进行等待

推荐使用的方式是: 阻塞的方法和超时的方法,这两套方法都是线程安全的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值