下面来分析线程执行类,线程池ThreadPool类

对该类的理解需要对java的线程池比较熟悉

该类引用了一个内部类

  1. /**
  2. * The lazily constructed LazyThreadPool instance.
  3. */
  4. private LazyThreadPool lazyThreadPool;

该成员实现了单例模式,即该对象只有一个实例,属于懒汉式单例模式,当实例化该成员时,启用了线程同步机制

  1. /**
  2. * Shut down the {@link ThreadPool}. After this returns
  3. * {@link ThreadPool#submit(TimedCancelable)} will return null.
  4. *
  5. * @param interrupt {@code true} if the threads executing tasks task should
  6. * be interrupted; otherwise, in-progress tasks are allowed to complete
  7. * normally.
  8. * @param waitMillis maximum amount of time to wait for tasks to complete.
  9. * @return {@code true} if all the running tasks terminated and
  10. * {@code false} if the some running task did not terminate.
  11. * @throws InterruptedException if interrupted while waiting.
  12. */
  13. synchronized boolean shutdown(boolean interrupt, long waitMillis)
  14. throws InterruptedException {
  15. isShutdown = true;
  16. if (lazyThreadPool == null) {
  17. return true;
  18. } else {
  19. return lazyThreadPool.shutdown(interrupt, waitMillis);
  20. }
  21. }
  22.  
  23. /**
  24. * Return a LazyThreadPool.
  25. */
  26. private synchronized LazyThreadPool getInstance() {
  27. if (lazyThreadPool == null) {
  28. lazyThreadPool = new LazyThreadPool();
  29. }
  30. return lazyThreadPool;
  31. }

线程提交方法如下

  1. /**
  2. * Submit a {@link Cancelable} for execution and return a
  3. * {@link TaskHandle} for the running task or null if the task has not been
  4. * accepted. After {@link ThreadPool#shutdown(boolean, long)} returns this
  5. * will always return null.
  6. */
  7. public TaskHandle submit(Cancelable cancelable) {
  8. if (isShutdown) {
  9. return null;
  10. }
  11. if (cancelable instanceof TimedCancelable && maximumTaskLifeMillis != 0L) {
  12. return getInstance().submit((TimedCancelable) cancelable);
  13. } else {
  14. return getInstance().submit(cancelable);
  15. }
  16. }

这里针对Cancelable对象类型和TimedCancelable类型提交到了不同的方法(多态)

提交Cancelable类型对象比较简单,提交任务后获取操作句柄

  1. /**
  2. * 提交任务2 获得操作句柄
  3. * Submit a {@link Cancelable} for execution and return a
  4. * {@link TaskHandle} for the running task or null if the task has not been
  5. * accepted. After {@link LazyThreadPool#shutdown(boolean, long)} returns
  6. * this will always return null.
  7. */
  8. TaskHandle submit(Cancelable cancelable) {
  9. try {
  10. // taskFuture is used to cancel 'cancelable' and to determine if
  11. // 'cancelable' is done.
  12. Future<?> taskFuture = completionService.submit(cancelable, null);
  13. return new TaskHandle(cancelable, taskFuture, clock.getTimeMillis());
  14. } catch (RejectedExecutionException re) {
  15. if (!executor.isShutdown()) {
  16. LOGGER.log(Level.SEVERE, "Unable to execute task", re);
  17. }
  18. return null;
  19. }
  20. }

而提交TimedCancelable类型对象则相对比较复杂

基本思路是,首先启动一个延迟执行的线程,即在指定的时间延迟后执行TimedCancelable类型对象的timeout()方法,即取消另外一个线程的执行,即超时检测线程;

然后启动另外一个线程执行TimedCancelable类型对象的run()方法,同时执行完毕后,则同时取消上面的超时检测线程(如果指定时间内未执行完毕,则由超时检测线程来取消执行)。

这里我们可以类比于守护线程与用户线程的关系,前面的超时检测线程好比守护线程,后者好比用户线程,当用户线程执行完毕后,守护线程也就没有存在的必要了

提交TimedCancelable类型对象方法如下

  1. /**
  2. * 提交任务1
  3. * Submit a {@link TimedCancelable} for execution and return a
  4. * {@link TaskHandle} for the running task or null if the task has not been
  5. * accepted. After {@link LazyThreadPool#shutdown(boolean, long)} returns
  6. * this will always return null.
  7. */
  8. TaskHandle submit(TimedCancelable cancelable) {
  9. try {
  10. // When timeoutTask is run it will cancel 'cancelable'.
  11. TimeoutTask timeoutTask = new TimeoutTask(cancelable);
  12.  
  13. // Schedule timeoutTask to run when 'cancelable's maximum run interval
  14. // has expired.
  15. // timeoutFuture will be used to cancel timeoutTask when 'cancelable'
  16. // completes.
  17. //延迟执行
  18. Future<?> timeoutFuture = timeoutService.schedule(timeoutTask,
  19. maximumTaskLifeMillis, TimeUnit.MILLISECONDS);
  20.  
  21. //cancelable执行完毕之后,超时线程不再执行
  22. // cancelTimeoutRunnable runs 'cancelable'. When 'cancelable' completes
  23. // cancelTimeoutRunnable cancels 'timeoutTask'. This saves system
  24. // resources. In addition it prevents timeout task from running and
  25. // calling cancel after 'cancelable' completes successfully.
  26. CancelTimeoutRunnable cancelTimeoutRunnable =
  27. new CancelTimeoutRunnable(cancelable, timeoutFuture);
  28.  
  29. // taskFuture is used to cancel 'cancelable' and to determine if
  30. // 'cancelable' is done.
  31. Future<?> taskFuture =
  32. completionService.submit(cancelTimeoutRunnable, null);
  33. TaskHandle handle =
  34. new TaskHandle(cancelable, taskFuture, clock.getTimeMillis());
  35.  
  36. // TODO(strellis): test/handle timer pop/cancel before submit. In
  37. // production with a 30 minute timeout this should never happen.
  38. timeoutTask.setTaskHandle(handle);
  39. return handle;
  40. } catch (RejectedExecutionException re) {
  41. if (!executor.isShutdown()) {
  42. LOGGER.log(Level.SEVERE, "Unable to execute task", re);
  43. }
  44. return null;
  45. }
  46. }

首先构造超时检测任务对象,该类为静态内部类

  1. /**
  2. * 静态内部类 检测线程超时
  3. * A task that cancels another task that is running a {@link TimedCancelable}.
  4. * The {@link TimeoutTask} should be scheduled to run when the interval for
  5. * the {@link TimedCancelable} to run expires.
  6. */
  7. private static class TimeoutTask implements Runnable {
  8. final TimedCancelable timedCancelable;
  9. private volatile TaskHandle taskHandle;
  10.  
  11. TimeoutTask(TimedCancelable timedCancelable) {
  12. this.timedCancelable = timedCancelable;
  13. }
  14.  
  15. public void run() {
  16. if (taskHandle != null) {
  17. timedCancelable.timeout(taskHandle);
  18. }
  19. }
  20.  
  21. void setTaskHandle(TaskHandle taskHandle) {
  22. this.taskHandle = taskHandle;
  23. }
  24. }

然后延迟执行该线程,获得Future<?> timeoutFuture线程句柄

  1. // Schedule timeoutTask to run when 'cancelable's maximum run interval
  2. // has expired.
  3. // timeoutFuture will be used to cancel timeoutTask when 'cancelable'
  4. // completes.
  5. //延迟执行
  6. Future<?> timeoutFuture = timeoutService.schedule(timeoutTask,
  7. maximumTaskLifeMillis, TimeUnit.MILLISECONDS);

然后构造CancelTimeoutRunnable对象,传入TimedCancelable类型对象和Future<?> timeoutFuture线程句柄

  1. //cancelable执行完毕之后,超时线程不再执行
  2. // cancelTimeoutRunnable runs 'cancelable'. When 'cancelable' completes
  3. // cancelTimeoutRunnable cancels 'timeoutTask'. This saves system
  4. // resources. In addition it prevents timeout task from running and
  5. // calling cancel after 'cancelable' completes successfully.
  6. CancelTimeoutRunnable cancelTimeoutRunnable =
  7. new CancelTimeoutRunnable(cancelable, timeoutFuture);

内部类LazyThreadPool的内部类CancelTimeoutRunnable

  1. /**
  2. * 内部类LazyThreadPool的内部类1
  3. * 执行TimedCancelable cancelable的run方法
  4. * 执行完毕后取消超时线程
  5. * A {@link Runnable} for running {@link TimedCancelable} that has been
  6. * guarded by a timeout task. This will cancel the timeout task when the
  7. * {@link TimedCancelable} completes. If the timeout task has already run,
  8. * then canceling it has no effect.
  9. */
  10. private class CancelTimeoutRunnable implements Runnable {
  11. private final Future<?> timeoutFuture;
  12. private final TimedCancelable cancelable;
  13.  
  14. /**
  15. * Constructs a {@link CancelTimeoutRunnable}.
  16. *
  17. * @param cancelable the {@link TimedCancelable} this runs.
  18. * @param timeoutFuture the {@link Future} for canceling the timeout task.
  19. */
  20. CancelTimeoutRunnable(TimedCancelable cancelable, Future<?> timeoutFuture) {
  21. this.timeoutFuture = timeoutFuture;
  22. this.cancelable = cancelable;
  23. }
  24.  
  25. public void run() {
  26. try {
  27. cancelable.run();
  28. } finally {
  29. timeoutFuture.cancel(true);
  30. timeoutService.purge();
  31. }
  32. }
  33. }

上面的run方法执行cancelable对象的run方法,执行完毕后取消超时线程并清理队列任务

后面部分是提交任务并获取线程操作句柄

  1. // taskFuture is used to cancel 'cancelable' and to determine if
  2. // 'cancelable' is done.
  3. Future<?> taskFuture =
  4. completionService.submit(cancelTimeoutRunnable, null);
  5. TaskHandle handle =
  6. new TaskHandle(cancelable, taskFuture, clock.getTimeMillis());
  7.  
  8. // TODO(strellis): test/handle timer pop/cancel before submit. In
  9. // production with a 30 minute timeout this should never happen.
  10. timeoutTask.setTaskHandle(handle);

shutdown方法关闭线程池

  1. /**
  2. * 关闭线程池任务
  3. * Shut down the LazyThreadPool.
  4. * @param interrupt {@code true} if the threads executing tasks task should
  5. * be interrupted; otherwise, in-progress tasks are allowed to
  6. * complete normally.
  7. * @param waitMillis maximum amount of time to wait for tasks to complete.
  8. * @return {@code true} if all the running tasks terminated, or
  9. * {@code false} if some running task did not terminate.
  10. * @throws InterruptedException if interrupted while waiting.
  11. */
  12. boolean shutdown(boolean interrupt, long waitMillis)
  13. throws InterruptedException {
  14. if (interrupt) {
  15. executor.shutdownNow();
  16. } else {
  17. executor.shutdown();
  18. }
  19. if (timeoutService != null) {
  20. timeoutService.shutdown();
  21. }
  22. try {
  23. return executor.awaitTermination(waitMillis, TimeUnit.MILLISECONDS);
  24. } finally {
  25. completionExecutor.shutdownNow();
  26. if (timeoutService != null) {
  27. timeoutService.shutdownNow();
  28. }
  29. }
  30. }

内部类LazyThreadPool的内部类CompletionTask用于获取线程结果

  1. /**
  2. * 内部类LazyThreadPool的内部类2
  3. * 获取结果线程
  4. * A task that gets completion information from all the tasks that run in a
  5. * {@link CompletionService} and logs uncaught exceptions that cause the
  6. * tasks to fail.
  7. */
  8. private class CompletionTask implements Runnable {
  9. private void completeTask() throws InterruptedException {
  10. Future<?> future = completionService.take();
  11. try {
  12. future.get();
  13. } catch (CancellationException e) {
  14. LOGGER.info("Batch terminated due to cancellation.");
  15. } catch (ExecutionException e) {
  16. Throwable cause = e.getCause();
  17. // TODO(strellis): Should we call cancelable.cancel() if we get an
  18. // exception?
  19. if (cause instanceof InterruptedException) {
  20. LOGGER.log(Level.INFO, "Batch terminated due to an interrupt.",
  21. cause);
  22. } else {
  23. LOGGER.log(Level.SEVERE, "Batch failed with unhandled exception: ",
  24. cause);
  25. }
  26. }
  27. }
  28.  
  29. public void run() {
  30. try {
  31. while (!Thread.currentThread().isInterrupted()) {
  32. completeTask();
  33. }
  34. } catch (InterruptedException ie) {
  35. Thread.currentThread().interrupt();
  36. }
  37. LOGGER.info("Completion task shutdown.");
  38. }
  39. }
  40. }

ThreadNamingThreadFactory为静态内部类,用于构造线程对象

  1. /**
  2. * A {@link ThreadFactory} that adds a prefix to thread names assigned
  3. * by {@link Executors#defaultThreadFactory()} to provide diagnostic
  4. * context in stack traces.
  5. */
  6. private static class ThreadNamingThreadFactory implements ThreadFactory {
  7. private final ThreadFactory delegate = Executors.defaultThreadFactory();
  8. private final String namePrefix;
  9.  
  10. ThreadNamingThreadFactory(String namePrefix) {
  11. this.namePrefix = namePrefix + "-";
  12. }
  13.  
  14. public Thread newThread(Runnable r) {
  15. Thread t = delegate.newThread(r);
  16. t.setName(namePrefix + t.getName());
  17. return t;
  18. }
  19. }

---------------------------------------------------------------------------

本系列企业搜索引擎开发之连接器connector系本人原创

转载请注明出处 博客园 刺猬的温驯

本人邮箱: chenying998179@163#com (#改为.)

本文链接 http://www.cnblogs.com/chenying99/p/3775701.html

企业搜索引擎开发之连接器connector(二十二)的更多相关文章

  1. 企业搜索引擎开发之连接器connector(十九)

    连接器是基于http协议通过推模式(push)向数据接收服务端推送数据,即xmlfeed格式数据(xml格式),其发送数据接口命名为Pusher Pusher接口定义了与发送数据相关的方法 publi ...

  2. 企业搜索引擎开发之连接器connector(十八)

    创建并启动连接器实例之后,连接器就会基于Http协议向指定的数据接收服务器发送xmlfeed格式数据,我们可以通过配置http代理服务器抓取当前基于http协议格式的数据(或者也可以通过其他网络抓包工 ...

  3. 企业搜索引擎开发之连接器connector(十六)

    本人有一段时间没有接触企业搜索引擎之连接器的开发了,连接器是涉及企业搜索引擎一个重要的组件,在数据源与企业搜索引擎中间起一个桥梁的作用,类似于数据库之JDBC,通过连接器将不同数据源的数据适配到企业搜 ...

  4. 企业搜索引擎开发之连接器connector(二十九)

    在哪里调用监控器管理对象snapshotRepositoryMonitorManager的start方法及stop方法,然后又在哪里调用CheckpointAndChangeQueue对象的resum ...

  5. 企业搜索引擎开发之连接器connector(二十八)

    通常一个SnapshotRepository仓库对象对应一个DocumentSnapshotRepositoryMonitor监视器对象,同时也对应一个快照存储器对象,它们的关联是通过监视器管理对象D ...

  6. 企业搜索引擎开发之连接器connector(二十六)

    连接器通过监视器对象DocumentSnapshotRepositoryMonitor从上文提到的仓库对象SnapshotRepository(数据库仓库为DBSnapshotRepository)中 ...

  7. 企业搜索引擎开发之连接器connector(二十五)

    下面开始具体分析连接器是怎么与连接器实例交互的,这里主要是分析连接器怎么从连接器实例获取数据的(前面文章有涉及基于http协议与连接器的xml格式的交互,连接器对连接器实例的设置都是通过配置文件操作的 ...

  8. 企业搜索引擎开发之连接器connector(二十四)

    本人在上文中提到,连接器实现了两种事件依赖的机制 ,其一是我们手动操作连接器实例时:其二是由连接器的自动更新机制 上文中分析了连接器的自动更新机制,即定时器执行定时任务 那么,如果我们手动操作连接器实 ...

  9. 企业搜索引擎开发之连接器connector(二十)

    连接器里面衔接数据源与数据推送对象的是QueryTraverser类对象,该类实现了Traverser接口 /** * Interface presented by a Traverser. Used ...

随机推荐

  1. Ubuntu各种indicator汇总

    1.  indicator-multiload: 可视化图形显示 sudo apt-get install indicator-multiload 2. indicator-sysmonitor: 以 ...

  2. vim配置之安装脚本

    vimConfig/install/install.sh git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle cp ...

  3. 三.jQuery源码解析之jQuery的框架图

    这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...

  4. Windows 远程桌面连接Ubuntu16.04图像界面

    1.安装xrdp sudo apt-get install xrdp 2. 安装vnc4server sudo apt-get install vnc4server 3. 安装xubuntu-desk ...

  5. django-引用静态文件

    1.需要配置settings # 静态文件目录 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') 2.页面加载静态文件 {% load sta ...

  6. 让别人能登陆你的mysql

    线上的数据库肯定是不能轻易在开发新功能的时候动的,如果你的数据库跟线上不一样了又没有新数据库的备份,就很麻烦. 当然去动线上数据库,出了什么问题我是不想背锅的. 最稳健的办法!让管理线上数据库的同学, ...

  7. 迷你MVVM框架 avalonjs 1.3.3发布

    大家可以在仓库中看到,多出了一个叫avalon.observe的东西,它是基于Object.observe,dataset, Promise等新API实现.其中,它也使用全新的静态收集依赖的机制,这个 ...

  8. open File Browser in shell

    [maxosx] open /usr/include [ubuntu] 发现三个,如下: xdg-open xxxx.pdf gnome-open . nautilus . 喜欢把它alias一下 . ...

  9. 14.Longest Common Prefix (String)

    Write a function to find the longest common prefix string amongst an array of strings. class Solutio ...

  10. 在Action中获取表单提交数据

    -----------------siwuxie095 在 Action 中获取表单提交数据 1.之前的 Web 阶段是提交表单到 Servlet,在其中使用 Request 对象 的方法获取数据 2 ...