java 并发与线程池

java并发包使用Executor框架来进行线程的管理,Executor将任务的提交与执行过程分开,直接使用Runnable表示任务。future获取返回值。ExecutorService 继承了Executor接口,提供生命周器的管理,包括运行,关闭,终止三种状态。

ThreadPoolExecutor

ThreadPoolExecutor 是ExecutorService的一个实现类。使用几个线程池来执行task,通常使用Executors工厂方法配置。

ThreadPoolExecutor 允许提供一个BlockingQueue来保存正在等待执行的task,队列一般有三种:无界,有界,和同步移交(synchronous handoff)。

newFixedThreadPool和newSingleThreadExecutor默认情况使用LinkedBlockingQueue。当任务增加的速度超过线程处理任务的速度时,队列大小会无限增加。会造成资源耗尽,内存溢出等问题。

所以使用有界队列比较稳妥,但是引入了新的问题,队列满了后,新的任务如何处理。这种情况引入了饱和策略,JDK提供了几种不同的饱和策略。

  • Abort(中止) 会扔出一个RejectedExecution Exception,开发者根据此处理自己的业务代码

  • CallerRunsPolicy 不会抛弃任务,也不会抛出异常。而是将某些task回退给调用者,降低新任务的流量。

无界队列:Executor提供的newFixedThreadPool和newSingleThreadExecutor在默认情况下将使用一个无界的LinkedBlockingQueue。无界队列当负载很大时,可能会导致资源耗尽

有界队列:ArrayBlockingQueue,

队列填满以后如何处理请求:

需要使用饱和策略:

1.就是reject,抛异常,开发者自己处理异常,决定策略。

2.丢给主线程,主线程去处理任务

在使用有界的工作队列时,队列的大小与线程池的大小必须一起调节,

同步移交:

对于非常大的或者无界的线程池,可以通过使用SynchronousQueue来避免排队,将任务从生产者直接移交给工作中线程。不放在工作队列里了

Executors

同时Executor也提供了线程池管理方法。可以调用Executors的静态工厂方法来创建一个线程池

  • newFixedThreadPool 固定大小的线程池,没达到最大线程数目时,提交一个任务创建一个线程,达到最大数目后,不再变化。

    1. public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    2. return new ThreadPoolExecutor(nThreads, nThreads,
    3. 0L, TimeUnit.MILLISECONDS,
    4. new LinkedBlockingQueue<Runnable>(),
    5. threadFactory);
    6. }
  • newCachedThreadPool 可缓存的线程池,没有线程最大数目限制。如果线程池当前规模超过了请求,就回收空闲线程,请求任务增加时,就添加新的线程。

  • newSingleThreadExecutor 单线程的Executor,如果线程异常结束,会创建另外一个线程来替代。确保任务在按队列中的顺序来串行执行。

  • newScheduledThreadPool 固定长度的线程池,而且以延迟或定时的方式来执行任务

一个sample code

  1. ExecutorService executor = Executors.newSingleThreadExecutor();
  2. Callable<List<String>> callable;
  3. callable = new Callable<List<String>>(){
  4. @Override
  5. public List<String> call() throws Exception {
  6. return readFile("src/concurrent/test.txt");
  7. }
  8. };
  9. Future<List<String>> future = executor.submit(callable);
  10. try {
  11. List<String> lines = future.get(5, TimeUnit.SECONDS);
  12. for(String line: lines) {
  13. System.out.println(line);
  14. }
  15. } catch (InterruptedException | ExecutionException | TimeoutException e) {
  16. // TODO Auto-generated catch block
  17. e.printStackTrace();
  18. }

完整源码stoneFang的github

Google Guava的并发库

https://github.com/google/guava/wiki/ListenableFutureExplained

JDK中Future通过异步的方式计算返回结果,当并发操作时,在任务结束或者没结束的时候都会返回一个结果。Future是异步操作的一个引用句柄,确保在服务执行返回一个结果。

ListenableFuture允许注册回调方法。可以一个小小的改进会支持更多的操作。

对应JDK中的 ExecutorService.submit(Callable) 提交多线程异步运算的方式,Guava 提供了ListeningExecutorService 接口, 该接口返回 ListenableFuture 而相应的 ExecutorService 返回普通的 Future。将 ExecutorService 转为 ListeningExecutorService,可以使用MoreExecutors.listeningDecorator(ExecutorService)进行装饰。

  1. ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
  2. ListenableFuture<Explosion> explosion = service.submit(new Callable<Explosion>() {
  3. public Explosion call() {
  4. return pushBigRedButton();
  5. }
  6. });
  7. Futures.addCallback(explosion, new FutureCallback<Explosion>() {
  8. // we want this handler to run immediately after we push the big red button!
  9. public void onSuccess(Explosion explosion) {
  10. walkAwayFrom(explosion);
  11. }
  12. public void onFailure(Throwable thrown) {
  13. battleArchNemesis(); // escaped the explosion!
  14. }
  15. });

与JDK的并发处理写了个对比的guava并发处理

  1. ```
  2. ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
  3. Callable<List<String>> callable;
  4. callable = new Callable<List<String>>(){
  5. @Override
  6. public List<String> call() throws Exception {
  7. return readFile("src/concurrent/test.txt");
  8. }
  9. };
  10. ListenableFuture<List<String>> future = executor.submit(callable);
  11. Futures.addCallback(future, new FutureCallback<List<String>>() {
  12. public void onFailure(Throwable thrown) {
  13. System.out.println("error");
  14. }
  15. @Override
  16. public void onSuccess(List<String> result) {
  17. for(String line: result) {
  18. System.out.println(line);
  19. }
  20. }
  21. });
  22. ```

源码在My Github

Cassandra的并发

cassandra在jdk的concurrent包上封装了自己的并发处理,同时也在各处调用原生的jdk并发包以及google的guava并发处理包

Cassandra并发框架

Figure1——cassandra并发实现

  1. cassandra各个Stage是通过StageManger来进行管理的,StageManager 有个内部类ExecuteOnlyExecutor。

  2. ExecuteOnlyExecutor继承了ThreadPoolExecutor,实现了cassandra的LocalAwareExecutorSerivce接口

  3. LocalAwareExecutorService继承了Java的ExecutorService,构建了基本的任务模型。添加了两个自己的方法.

    execute方法用于trace跟踪。

    1. public void execute(Runnable command, ExecutorLocals locals);
    2. public void maybeExecuteImmediately(Runnable command);

    对于Executor中的默认execute方法,和LocalAwareExecutorSerive中的execute方法都是new 一个task,然后将task添加到queue中。而maybeExecuteImmedicatly方法则是判断下是否有正在执行的task或者work,如果没有则直接执行,而不添加到队列中。

    1. public void maybeExecuteImmediately(Runnable command)
    2. {
    3. //comment1
    4. FutureTask<?> ft = newTaskFor(command, null);
    5. if (!takeWorkPermit(false))
    6. {
    7. addTask(ft);
    8. }
    9. else
    10. {
    11. try
    12. {
    13. ft.run();
    14. }
    15. finally
    16. {
    17. returnWorkPermit();
    18. maybeSchedule();
    19. }
    20. }
    21. }
  4. AbstractLocalAwareExecutorService实现LocalAwareExecutorSerive接口,提供了executor的实现以及ExecutorServie接口中的关于生命周期管理的方法实现,如submit,shoudown等方法。添加了addTask,和任务完成的方法onCompletion。

  5. SEPExecutor实现了LocalAwareExecutorService类,提供了addTask,onCompletion,maybeExecuteImmediately等方法的实现。同时负责队列的管理

  6. SharedExecutorPool,线程池管理,用来管理Executor

Cassandra并发例子FlushWriter

  1. org.apache.cassandra.tools.nodetool.Flush
  2. org.apache.cassandra.service.StorageService.forceKeyspaceFlush
  3. org.apache.cassandra.db.ColumnFamily.forceBlockingFlush
  4. org.apache.cassandra.db.ColumnFamily.forceFlush
  5. public ListenableFuture<?> forceFlush(ReplayPosition flushIfDirtyBefore)
  6. {
  7. //1.需要处理的memtable data
  8. synchronized (data)
  9. {
  10. // memtable 的flush过程需要同时flush secondary index
  11. // during index build, 2ary index memtables can be dirty even if parent is not. if so,
  12. // we want to flush the 2ary index ones too.
  13. boolean clean = true;
  14. for (ColumnFamilyStore cfs : concatWithIndexes())
  15. clean &= cfs.data.getView().getCurrentMemtable().isCleanAfter(flushIfDirtyBefore);
  16. if (clean)
  17. {
  18. // We could have a memtable for this column family that is being
  19. // flushed. Make sure the future returned wait for that so callers can
  20. // assume that any data inserted prior to the call are fully flushed
  21. // when the future returns (see #5241).
  22. ListenableFutureTask<?> task = ListenableFutureTask.create(new Runnable()
  23. {
  24. public void run()
  25. {
  26. logger.trace("forceFlush requested but everything is clean in {}", name);
  27. }
  28. }, null);
  29. //执行flush的线程
  30. postFlushExecutor.execute(task);
  31. return task;
  32. }
  33. return switchMemtable();
  34. }
  35. }

data

就是Memtables,以及在磁盘上的SSTables。需要使用synchronize来确保隔离性。在CF类初始化的时候会进行加载

public ColumnFamilyStore(Keyspace keyspace,

String columnFamilyName,

int generation,

CFMetaData metadata,

Directories directories,

boolean loadSSTables,

boolean registerBookkeeping)

{

  1. data = new Tracker(this, loadSSTables);
  2. if (data.loadsstables)
  3. {
  4. Directories.SSTableLister sstableFiles = directories.sstableLister(Directories.OnTxnErr.IGNORE).skipTemporary(true);
  5. Collection<SSTableReader> sstables = SSTableReader.openAll(sstableFiles.list().entrySet(), metadata);
  6. data.addInitialSSTables(sstables);
  7. }
  8. }

postFlushExecutor.execute(task);调用的就是ThreadPoolExecutor

  1. private static final ExecutorService flushExecutor = new JMXEnabledThreadPoolExecutor(1,
  2. StageManager.KEEPALIVE,
  3. TimeUnit.SECONDS,
  4. new LinkedBlockingQueue<Runnable>(),
  5. new NamedThreadFactory("MemtableFlushWriter"),
  6. "internal");

参考

stoneFang的github

https://wizardforcel.gitbooks.io/guava-tutorial/content/16.html

读Cassandra源码之并发的更多相关文章

  1. 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 百篇博客分析OpenHarmony源码 | v25.01

    百篇博客系列篇.本篇为: v25.xx 鸿蒙内核源码分析(并发并行篇) | 听过无数遍的两个概念 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度 ...

  2. 【读fastclick源码有感】彻底解决tap“点透”,提升移动端点击响应速度

    申明!!!最后发现判断有误,各位读读就好,正在研究中.....尼玛水太深了 前言 近期使用tap事件为老夫带来了这样那样的问题,其中一个问题是解决了点透还需要将原来一个个click变为tap,这样的话 ...

  3. 读jQuery源码 - Deferred

    Deferred首次出现在jQuery 1.5中,在jQuery 1.8之后被改写,它的出现抹平了javascript中的大量回调产生的金字塔,提供了异步编程的能力,它主要服役于jQuery.ajax ...

  4. 读 Zepto 源码之内部方法

    数组方法 定义 var emptyArray = [] concat = emptyArray.concat filter = emptyArray.filter slice = emptyArray ...

  5. 读 zepto 源码之工具函数

    Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目标对象的同名属性会被源对象的 ...

  6. 读 Zepto 源码之神奇的 $

    经过前面三章的铺垫,这篇终于写到了戏肉.在用 zepto 时,肯定离不开这个神奇的 $ 符号,这篇文章将会看看 zepto 是如何实现 $ 的. 读Zepto源码系列文章已经放到了github上,欢迎 ...

  7. 读Zepto源码之集合操作

    接下来几个篇章,都会解读 zepto 中的跟 dom 相关的方法,也即源码 $.fn 对象中的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码 ...

  8. 读 Zepto 源码之集合元素查找

    这篇依然是跟 dom 相关的方法,侧重点是跟集合元素查找相关的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zept ...

  9. 读Zepto源码之操作DOM

    这篇依然是跟 dom 相关的方法,侧重点是操作 dom 的方法. 读Zepto源码系列文章已经放到了github上,欢迎star: reading-zepto 源码版本 本文阅读的源码为 zepto1 ...

随机推荐

  1. nodejs中处理回调函数的异常

    如果是使用nodejs+express3这个经典的组合,那么有一种很方面的处理回调函数异常的方法: 1. 安装模块:express-domain-middleware 2. 加入如下的代码: app. ...

  2. python selenium模拟滑动操作

    selenium.webdriver提供了所有WebDriver的实现,目前支持FireFox.phantomjs.Chrome.Ie和Remote quit()方法会退出浏览器,而close()方法 ...

  3. TestNG监听器实现用例运行失败自动截图、重运行功能

    注: 以下内容引自 http://blog.csdn.net/sunnyyou2011/article/details/45894089 (此非原出处,亦为转载,但博主未注明原出处) 使用Testng ...

  4. 作为比湖南还火的python网红,零基础要如何系统的开始学习呢?

    Python(发音:英[?pa?θ?n],美[?pa?θɑ:n]),是一种面向对象.直译式电脑编程语言,也是一种功能强大的通用型语言,已经具有近二十年的发展历史,成熟且稳定.它包含了一组完善而且容易理 ...

  5. i春秋——Misc之百度杯

    今天心里很是不开森,想想往日何必那么努力呢?不如你的比比皆是,可是人家就是因为有关系,你又能怎样呢? 你所有应该有的都被打翻了,别灰心,至少你曾经努力过! 愿我未来的学弟学妹们都能一直开开心心的过好每 ...

  6. mysql中利用group by过滤删除重复行

    DELETEFROM peopleWHERE peopleId IN (SELECT peopleId FROM people GROUP BY peopleId HAVING count(peopl ...

  7. 什么是语义化的HTML?为什么要做到语义化?

    一.什么是语义化的HTML? 语义化的HTML就是写出的HTML代码,符合内容的结构化(内容语义化),选择合适的标签(代码语义化),能够便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地 ...

  8. js模块化 javascript 模块化 闭包写法 闭包模块化写法

    var main = main || {}; ; (function (main) { 'use strict'; //私有变量 var _s1 = 'Hello '; var _s2 = 'Worl ...

  9. 响应式WEB设计的基本原则大总结

    响 应式Web设计对于解决多类型屏幕问题来说是个不错方案,但从印刷的角度来看,其却存在着很多的困难.没有固定的页面尺寸.没有毫米或英寸,没有任何物理 限制,让人感到无从下手.随着建立网站可用的各种小工 ...

  10. 解决:git push error: failed to push some refs to

    出现错误的原因是github中的README.md文件不在本地代码目录中. 也就是说我们需要先将远程代码库中的任何文件先pull到本地代码库中,才能push新的代码到github代码库中. 使用如下命 ...