> (b) The second approach is to draw a very simple, square box, and say: "You
> must program in the box". We can completely describe the box in no more
> than a few pages, and provide them with static and dynamic tools for
> testing if they are in the box. One simple box is "Use must use
> synchronization or volatile variables to communicate between threads".
I am sympathetic to this, but in addition to the problems Joe
mentioned (i.e., mainly, that simple != intuitive), there are some
other interrelated concerns:
1. A simple rule that requires extra synchronizations on machines that
do not really need it will be difficult to maintain unless VMs on
those machines are able to simply remove this overhead when it is
not needed. People running on pentiums, sparcs, and other machines
with relatively strong memory models should not be penalized.
Performance concerns are great enough in Java that most people
just won't write to a spec that slows down their programs by a
significant factor on the platforms it normally runs on. Rather
than, or in addition to relying on optimizations, this seems to
argue for inclusion of constructs or provisions that can take
advantage of stronger memory models when they are present but will
need to be implemented in a more costly fashion on other
machines. "Final" is one of these. Full initialization safety is
another (although as we have argued, not necessarily a desirable
one).
2. Analysis tools are useful, but almost all QA these days is
test-driven. If a program passes tests on platforms people have
around, they declare success, regardless of whether the spec says
that the program would not work under the officially sanctioned
memory model. Unless every JDK came with a special testing VM that
simulated the weakest possible behavior in accord with the model,
many people would not pay enough attention to counterintuitive,
performance-limiting rules.
(A corollary of sorts is that many people have learned to
program to the current implementations of Java/JDK features,
not to their specifications. This is of course a bad thing,
but is a basic survival skill for people who have to ship
products on schedule.)
3. The linkage between locks and memory barriers is OK in most
contexts, but very troubling in others. Locks of course have their
disadvantages; most obviously in that the more locks you use, the
more likely it is that you've introduced an unforseen deadlock or
lockout condition. (*) Many systems-level designers are increasingly
moving to more optimistic techniques. See for example Mike
Greenwald's thesis at
http://www.cis.upenn.edu/~mbgreen/MichaelGreenwald.html
While most of these can be simulated by using internal private
locks to implement CAS etc. (with some performance loss), it
might be worth considering memory rules and even other language
features that are not directly tied to locks.
(*) While tools to conservatively determine certain potential
data races are relatively easy to construct, analytic
deadlock detetection in most Java programs is essentially
impossible since deadlock detection is non-modular. For
example, any program that involves dynamic loading cannot
be fully checked.
4. The model should make it possible for library and framework
providers to help other programmers write fast, reliable code.
I and others sometimes spend months coming up with legal,
fast, solutions so that other programmers won't be tempted to do
it themselves and almost always get it wrong. This might sometimes
argue for less simple rules that are known to be consistent with
an overall model but make way for better performance. In
particular, I would hate to see a model under which the only path
to good performance for some of these classes and utilities would
be to resort to native code. You should be able to write these
things at least as efficiently in Java proper.
-Doug
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:21 EDT