Deterministic Parallel Java Brings Safety and Modularity to Parallel Programming

The first release of Deterministic Parallel Java packed a lot of "firsts" into its debut. The parallel language, developed by researchers at UPCRC Illinois, is the first to guarantee deterministic semantics without run-time checks for general-purpose, object-oriented programs. It's also the first language to use compile-time type checking for parallel operations on arrays of references ("pointers") to objects, and the first language to use regions and effects for flexible, nested data structures.

And if that's not enough, the yet-to-be-released experimental versions promise even more. Such as the first language to guarantee deterministic use of object-oriented parallel frameworks. Or even the first language to allow safe mixing of deterministic and non-deterministic code -- which greatly simplifies reasoning about such software.

When Illinois Computer Science professor Vikram Adve, together with his Ph.D. student Robert Bocchino and the rest of his team, set out to address the challenge of "making parallelism easy," they focused on developers and their needs. They wanted to develop a language that supports programming styles developers find most familiar and productive, such as mainstream object-oriented programming languages.

Their broad goal was to provide deterministic-by-default semantics for an object-oriented, imperative parallel language, using primarily compile-time checking. "Deterministic" to produce the same visible output for a given input -- always. "By default" to guarantee deterministic behavior -- that is unless the programmer explicitly requests otherwise. The result is DPJ, a safe and modular parallel language that helps developers port (parts of) sequential Java applications to run on multicore systems. It also helps them rewrite (parts of) parallel Java applications to simplify debugging, testing, and long-term maintenance. DPJ-ported parallel code can co-exist with ordinary Java code within the same application, so that programs can be incrementally ported to DPJ.

DPJ simplifies debugging and testing of parallel software as all potential data races are caught at compile-time. Because DPJ programs have obvious sequential semantics, all debugging and testing of DPJ code can happen essentially like that for sequential programs. Maintenance becomes easier as DPJ encodes the programmer's knowledge of parallel data sharing patterns in DPJ annotations -- simplifying the tasks of understanding, modifying, and extending parallel DPJ software. Moreover, thanks to the same program annotations, each function or class can be understood and parallelized in a modular fashion, without knowing internal parallelism or synchronization details of other functions or classes. This is especially important because modularity is crucial for creating large scale software applications, but modularity is severely compromised when using any of today's mainstream shared memory programming models.