Concurrencer is a refactoring tool, which helps programmers refactor sequential java code with the help of j.u.c (java.util.concurrent). Compared with find-and-replace refactoring transformations, its transformations are more complex as they require program analysis and may spawn multiple, non-adjacent, program statements.
The motivation behind implementing such a tool is based on the fact that there are many cases where retrofitting concurrency is easier than rewriting it. Doing this manually is tedious as it may require changing many lines of code; it is error-prone because one can easily choose the wrong refactoring API when multiple of them are available; and at the same time omission-prone as it is always hard to manually choose the most efficient API alternative when more of them are available.
There are three types of behavior preserving refactorings supported in Concurrencer: converting int to AtomicInteger, converting HashMap to ConcurrentHashMap and the most laborious, converting recursion to ForkJoinTask. The first two transformations enable a sequential program to become thread safe, a thread safe program become more scalable, while the third makes a sequential program run concurrently, with obvious performance improvements. When refactoring, it is the programmer’s responsibility to identify all the shared data and a target refactoring. It is then Concurrencer’s responsibility to analyze all the accesses to shared data and apply the transformations in the best possible way.
When refactoring to AtomicInteger and ConcurrentHashMap there are interesting aspects regarding the initialization and field access of the affected variables, however what is worth mentioning is how Concurrencer is dealing with existing synchronization primitives. Typically if the original code contains synchronized accesses around the fields, Concurrencer removes them since this becomes superfluous after the transformation as the new types have built-in thread safety.
The third and the most interesting transformation, relies on the support of the ForkJoinTask framework available in Java 7. Divide-and-conquer programs are the best candidates for this framework offering support for fine grained parallelism in computationally intensive applications. Using the user supplied threshold, which defines the size of the problem that can be solved sequentially, along with the divide-and-conquer method, Concurrencer creates the task java classes by subclassing from RecursiveAction class and encapsulating the parallel computation of the original recursive method, changes the base of the recursion, replaces recursive calls with task instantiations, then executes the parallel tasks and combines the results of the subtasks.
While covering most common refactoring scenarios, Concurrencer is not complete. However even though the approach is neither sound nor complete, it is still useful as it saves programmer’s time overall. Moreover, it is very easy to extend these transformation patterns to cover more refactoring scenarios.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment