Java源码分析
来源:互联网 发布:医学英文写作软件 编辑:程序博客网 时间:2024/06/09 16:38
前言
最近在处理多线程的问题上.频繁的听到Join/Fork这个名词,在学习多线程的时候也有介绍过,太久没有基本都忘记了.
首先介绍几篇关于Fork/Join的文章
1.Fork and Join: Java Can Excel at Painless Parallel Programming Too!
2.《Java 7并发编程实战手册》第五章Fork/Join框架
需要先了解一下Fork/Join的相关知识,再来读本文章.本文章主要分析ForkJoinTask类.使用版本是Java8.
多线程发展历程
Thread => Executor => Fork/Join
在我们进行普通多线程的操作时候,我们通常会使用Thread和Runnable去操作,
但是我们通常没有办法很好管理.
到Java1.5时候Executor诞生,有效的帮我们管理起这些线程的状态.
Java7时,就诞生了Fork/Join框架.框架的核心思想是将问题拆分成小任务,然后在将产生的结果合并.思想很类似于MapReduce,有兴趣可以去了解一下.
ForkJoinTask源码分析
本文章只解析几个关键的方法(常用的方法)以及他们所涉及的方法.
fork方法
fork方法是属于所有方法的基石,将我们的任务进行拆分.下面看一下源码.
//设计成fianl让子类无法去破坏. public final ForkJoinTask<V> fork() { Thread t; //如果当前的线程是Fork/join的线程,就添加到队列中 if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ((ForkJoinWorkerThread)t).workQueue.push(this); else //当task是直接被调用,而不是使用ForkJoinWorkerThread的话,直接执行任务. ForkJoinPool.common.externalPush(this); return this; }
这里需要注意的是workqueue是ForkJoinPool的一个内部类对象.并且workQueue不是没有继承queue接口,具体实现有兴趣的可以了解一下,以后也许会分析一下.今天还是主要讲ForkJoinTask.
final ForkJoinPool.WorkQueue workQueue;
如果不是则执行任务.这个方法的解析放在ForkJoinPool进行讲解.
Join方法
执行子任务并合并子任务的结果集.下面详细介绍
public final V join() { int s; //执行任务 if ((s = doJoin() & DONE_MASK) != NORMAL) reportException(s); return getRawResult(); } private int doJoin() { int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w; //判断执行的状态 return (s = status) < 0 ? s : //判断是否fork/join的线程 ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ? //判断是否在队列的头部 && 在执行头部 (w = (wt = (ForkJoinWorkerThread)t).workQueue). tryUnpush(this) && (s = doExec()) < 0 ? s : //加入到等待的队列 wt.pool.awaitJoin(w, this, 0L) : //不是fork/join线程 阻塞 externalAwaitDone(); }
doJoin方法是进行合并,合并之前需要进行判断,看当前的任务是否可以执行,如果可以执行则调用doExec方法,如果不能执行则加入等待的队列.这里简单看一下awaitJoin方法
final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) { int s = 0; if (task != null && w != null) { //获取上一个task ForkJoinTask<?> prevJoin = w.currentJoin; U.putOrderedObject(w, QCURRENTJOIN, task); //判断是否为CountedCompleter对象 是ForkJoinTask的一个子类,可以理解为一种拓展 CountedCompleter<?> cc = (task instanceof CountedCompleter) ? (CountedCompleter<?>)task : null; for (;;) { if ((s = task.status) < 0) break; if (cc != null) helpComplete(w, cc, 0); //再次判断是否为顶部,尝试执行和移除task else if (w.base == w.top || w.tryRemoveAndExec(task)) helpStealer(w, task); //再次判断 if ((s = task.status) < 0) break; long ms, ns; if (deadline == 0L) ms = 0L; else if ((ns = deadline - System.nanoTime()) <= 0L) break; else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L) ms = 1L; if (tryCompensate(w)) { task.internalWait(ms); U.getAndAddLong(this, CTL, AC_UNIT); } } U.putOrderedObject(w, QCURRENTJOIN, prevJoin); } return s; }
在awaitJoin中会执行ryRemoveAndExec方法
final boolean tryRemoveAndExec(ForkJoinTask<?> task) { ForkJoinTask<?>[] a; int m, s, b, n; //判断是否为空 if ((a = array) != null && (m = a.length - 1) >= 0 && task != null) { //遍历 找到task,尝试进行执行和删除操作 while ((n = (s = top) - (b = base)) > 0) { for (ForkJoinTask<?> t;;) { // traverse from s to b long j = ((--s & m) << ASHIFT) + ABASE; if ((t = (ForkJoinTask<?>)U.getObject(a, j)) == null) return s + 1 == top; // shorter than expected else if (t == task) { boolean removed = false; if (s + 1 == top) { // pop if (U.compareAndSwapObject(a, j, task, null)) { U.putOrderedInt(this, QTOP, s); removed = true; } } else if (base == b) // replace with proxy //移除 removed = U.compareAndSwapObject( a, j, task, new EmptyTask()); if (removed) //执行task里面的任务 task.doExec(); break; } else if (t.status < 0 && s + 1 == top) { if (U.compareAndSwapObject(a, j, t, null)) U.putOrderedInt(this, QTOP, s); break; // was cancelled } if (--n == 0) return false; } if (task.status < 0) return false; } } return true; }
我们主要的目的是引出 task.doExec()方法,其他的关于ForkJoinPool方法不做过多讲解.在分析ForkJoinPool类时再仔细讲解.
doExec方法主要代码如下
final int doExec() { int s; boolean completed; //判断状态,是否执行 if ((s = status) >= 0) { try { //执行 completed = exec(); } catch (Throwable rex) { return setExceptionalCompletion(rex); } //完成任务,修改状态 if (completed) s = setCompletion(NORMAL); } return s; }//执行,最终还是调用我们子类复写的 compute()方法protected final boolean exec() { compute(); return true; }
从这整个流程可以看出,ForkJoinTask最终是一个循环,我们在compute方法中不能再继续拆分的时候循环才会结束,和我们了解的拆分机制很吻合.然后我们在将结果一级一级的进行合并.最终结束任务.
我们在ForkJoinTask类中,只是了解了task的执行流程,为此我们还看不出工作窃取功能
,我们需要在ForkJoinPool类中进行了解.
本文章还涉及到了Unsafe类的操作.本文章主要使用了Unsafe类中的原子操作的特性进行数据操作.关于详细内容大家可以自行去了解.
RecursiveAction&&RecursiveTask
RecursiveAction是ForkJoinTask的一个子类,通常用于不用返回结果的Task
RecursiveTask是ForkJoinTask的一个子类,通常用于有返回结果的Task
//RecursiveAction的exec方法 protected final boolean exec() { this.compute(); return true;}//RecursiveTask的exec方法 protected final boolean exec() { result = compute(); return true; }
结语
本文暂时就ForkJoinTask类的Fork方法和Join方法展开讲解,其他方法暂时没有用上,以后再对有需要的方法进行补充,
通过这两个方法我们了解到ForkJoinTask是如何对任务进行拆分和结果合并的。本人能力有限,如有什么不合理或者错误的地方,欢迎批评和指正。
- Java源码分析:Iterator
- Java Thread源码分析
- java Thread 源码分析
- Java HashMap 源码分析
- 深入JAVA源码分析
- java HashMap源码分析
- Java LinkedLIst 源码分析
- java BufferdInputStream源码分析
- java Thread源码分析
- java ReentrantLock源码分析
- java io源码分析
- 【java源码分析】-LinkedList
- java Condition源码分析
- Java BlockingQueue 源码分析
- Java BlockingQueue 源码分析
- Java ArrayList源码分析
- Java ArrayList 源码分析
- Java Vector 源码分析
- Deer的英语学习之路--为伊消得人憔悴-2017.09.30
- html animate可以制作动画
- JS window.onload笔记
- mysql常用的sql语句收集
- 高级Lyapunov稳定性
- Java源码分析
- AD的“Un-Routerd Net Constraint:......”报错处理
- MongoDB 各种命令
- (算法分析Week4)Median of Two Sorted Arrays[Hard]
- 使用Mongo Connector和Elasticsearch实现模糊匹配
- Conquer a New Region HDU
- SpringMVC ajax技术无刷新文件上传下载删除示例
- sql(join on 和where的执行顺序)
- Db2性能问题:临时表空间太大,导致连不上数据库