Re: Are there real use cases with the Java access modes?

Alex Otenko via Concurrency-interest <[email protected]> Wed, 21 Jul 2021 10:11:55 +0100
Newsgroups gmane.comp.java.jsr.166-concurrency
Message-ID <CANkgWKjdRGfJd6YXqgDs_uqX0O1S6Qurv+8tGv_1UaLUwh3tmw@mail.gmail.com>
I don't think I have ever said that it is not a problem. I think I have
been clear that if there is misunderstanding of what non-volatile accesses
do, there is a bigger problem, so "solving" the "unexpected" hoist is not
going to make the program correct.

For one, non-volatile accesses are allowed to happen in any order. The
example you gave just waits for a flag to be flipped, then do nothing
exciting. Try to read some variables instead. Even in pre-1.5 reorderings
happened.

I am particularly amazed at some claims about interactions with AWT and
even Kafka. How can one program for these, and not think of threads? Ok, I
know, many will learn Java from stackoverflow. But once you open
documentation about AWT or Swing, thread-(un)safety clauses are all over it.

The principle of least astonishment is misapplied, too. Astonishment to
whom? In C all loops terminate, so a C programmer may be astonished that
the loop you gave as an example does anything at all, if we throw away
everything out of the loop body. A Python or Javascript programmer may be
astonished that that loop ever terminates, because it never yields control
to a routine that mutates the flag. A Rust programmer may be surprised that
it compiles - mutability is not a given.


Alex

On Wed, 21 Jul 2021, 05:05 Gregg Wonderly via Concurrency-interest, <
[email protected]> wrote:

> I have suggested that the default of non-volatile was a problematic
> choice, because it creates surprise behavior out of compiler optimization
> of non-volatile references for even simple applications.  We all can agree
> that we used to write C and C++ code like the following, and having an
> optimizer do this for us, seems awesome.
>
> {
> register cpyA = A;
> register cpyB = B;
>
> … do something as fast as possible with cpyA and cpyB values…
> }
>
> My experience with this hoist optimization, early on, was a problem that I
> didn’t enjoy.  There were all kinds of circumstances that made it extremely
> difficult for me to fix my applications to work with JDK 1.5 and get the
> updates to all the unknown users since my jar files had been circulated
> without any formal distribution system.  So, I have a raw feeling about
> this particular “optimization” that wasn’t something I elected to use.  The
> JLS already described volatile keyword use, it wasn’t something that had
> used because I hadn’t encounter any such optimization prior to JDK 1.5 and
> the JMM clarifications of all the things that were underspecified before
> that.
>
> I am bring this up again, because if there are new language and JVM
> features happening, I’d like to see if there is some kind of solution for
> this particular issue that would at least allow inexperienced developers as
> well as experienced developers maintaining broken code that they haven’t
> seen a problem with yet.  Because this is a pretty silent optimization and
> because it’s so conditional on the code around it, my simple observation is
> that it’s a large surprise when the status of the hoist changes when you
> change code around the hoist.  Logic control statements in particular that
> have the hoist conditionally happen creates the surprise moment for people
> who don’t really understand that volatile is required to make swing
> applications that have listener callbacks manipulating data that the main
> thread is using.
>
> I have a class that I wrote a long time ago to make the AWT-only vs
> external-data creator details easier.  Here’s how a listener would use it
> to cause an action to occur when a button is pressed or menu item selected
> etc.
>
> public void ActionPerformed( ActionEvent ev ) {
> new ComponentUpdateThread<DataValues>( btn1, btn2, lbl1, lbl2, lbl3, txt1,
> txt2, pnlA ) {
> public void setup() { // on AWT event thread
> super.setup();   // disable all controls in cons
> txt1.setText( “” );
> txt2.setText(“”);
> }
> public DataValues construct() {  // Executes on random pool thread
> try {
> DataValues v = NetworkAPI_to_getData();
> return v;
> } catch( Exception ex ) {
> reportException(ex);
> }
> return null;
> }
> public void finish() {  // on AWT event thread
> DataValues v = getResults();
> txt1.setText(v.data1);
> txt2.setText(v.data2);
> super.finish();  // Enable all components
> }
> }.start();
> }
>
> This covers the exchange of data values between threads.  It also manages
> the access to the AWT component hierarchy so that it’s done with only an
> AWT event queue thread.  However, it still doesn’t cover the issue of
> non-volatile vs volatile value references between threads like my loop
> control example.  That’s why I am talking about this again and again.
> There is literally no way that simple value references can be passed
> between threads without eliminating the hoist.  You just cannot pass the
> value between threads, and this means that everyone has to understand
> exactly how the AWT event queue threads work and that anything that one of
> those “listener bits” reads or writes, which is also read or written by the
> main threads has to be volatile.  I am not claiming that just completely
> eliminating the hoist from the compiler is the only solution.   I am just
> trying to describe all the details that I see and have experience about
> this one particular language feature and how swing in particular has a
> common code design that can happen to developers of new applications, early
> in the development, that is frustrating to figure out.  And I also
> mentioned that the bigger issue is that this optimization is based on code
> structure that is far more reaching analysis than most optimizations and
> that implies further surprise when the optimization changes what’s executed.
>
> Yes I’ve been around Java from the beginning of it hitting the internet. I
> went to the NYC meeting where we saw applets in Mosaic.  I was on the Sun
> developer advisory council so I got to meet a lot of different people in
> Sun and in the Java community who were also participating there, such as
> Doug.  But I am not trying to say that makes me an expert.  I still have a
> whole lot less knowledge that the people on this list.
>
> I brought this up in the past and Alex and I have gone back and forth
> about it and he’s constantly contended that this is either not a problem or
> that it’s such a rare thing that it doesn’t matter.   As a long time Java
> proponent, I am frustrated about various things that have happened around
> the “Java is a server platform” mantra that many of the people pulling
> strings in this community and others.  I write code from the bottom to the
> top of the software stack.  I do nothing on the web, because I prefer
> native apps better and I feel like Swing had the opportunity to solve a lot
> of portability problems and allow UNIXish OSes to have an easy to use GUI
> environment.  But there were all kinds of problems around missing APIs to
> simplify things.  There were too many ways to get screwed over by the
> threading mode because there wasn’t anything explicit, like the API I
> showed above.  Even in code like netbeans, people were using the AWT even
> thread to make network connections specifically because of the non-volatile
> data sharing problem.  It’s really everywhere, and I don’t know how else to
> illustrate that this creates a really large difficulty in places where
> ’small’ data exchanges are frequent and everywhere.  People just don’t
> create large data structures and wrapper APIs that can solve this simple
> issue of hoisting references, because you can’t solve it simply by an API,
> because you still need both threads to know about some reference or use
> some rendezvous mechanism to exchange a value through a class wrapped
> reference that is managed appropriate in declaration and happens before.
>
> Gregg
>
>
> On Jul 20, 2021, at 8:39 PM, Joe Bowbeer via Concurrency-interest <
> [email protected]> wrote:
>
> Gregg,
>
> You've been involved off-and-on in the concurrency and JMM discussions for
> over 20 years, if I recall correctly.
>
> Are you proposing that an existing optimization now be disallowed? Is this
> a new proposal (from you), or has your argument changed?
>
> (For example, now you are arguing that our understanding of Java's
> intended audience is different than it was 20+ years ago?)
>
>
> On Tue, Jul 20, 2021, 12:29 PM Gregg Wonderly via Concurrency-interest <
> [email protected]> wrote:
>
>> Andrew, I appreciate all of the details you enumerate below about the
>> design of Java and how concurrency with multi-threading is a primary design
>> element.  The reference hoist has nothing to do with that though.  It has
>> to do with optimizing the execution time of a block of code.  Yes, the
>> analysis takes all the details of concurrent access into consideration
>> around code paths of this thread, able to reach back into the class in some
>> form.  But that analysis is totally based on the ‘volatile’ nature of the
>> value, not simply on the fact that we are in a language that provides APIs
>> that allow multi-threading to work.
>>
>> I understand that the specifics seem integrated.  But my perspective is
>> still that this reference hoist is assuming something that is so difficult
>> to prove and variable based on what can be proved, that it’s an alarming
>> side effect that is a surprise, more than it is a discernible behavior
>> without extensive knowledge to all the implementation details which control
>> when the hoist can actually occur.  Yes, that is what optimization is
>> about, but the reality is that this optimization breaks the logic of the
>> application and this is observable even in a debugger because of the logic
>> change due to the hoisted read.  Other language compilers have over decades
>> of development broken code due to mis-architected optimizations and we’ve
>> not left them in.
>>
>> The contention I am sensing revolves around the fact that this single
>> optimization would appear to be something that everyone is relying on to
>> solve lots of performance problems.  In days gone by of C and C++
>> programming, block-level, copy-of-value declarations were used as a moment
>> to copy needed immutable references into block level values as a form of
>> optimization of reference.  Things like
>>
>> SomeType val;
>> if( ( val = externVal) != null ) {
>> …lots of references to val...
>> }
>>
>> As a general non-locking mutation scheme, copy and replace (via CAS)
>> reference strategies are ever present in concurrent systems, to avoid
>> locks.  There’s just so many things that are done explicitly and provide
>> such better documentation than a compiler optimization does.
>>
>> The recurring counter point over the years, has been that experienced
>> software developers can know why this occurs and will be able to readily
>> fix the problem.  Really, believing that as a precursor to inaction, I
>> feel, is a pretentious attitude that has caused a lot of people to not
>> participate in many discussions.  It speaks to the belief that one can and
>> does know everything, and that’s the only way to be a real software
>> developer.  I’ve tried to have this discussion for years in a productive
>> way.  But repeatedly, we arrive at “those are not real developers and so we
>> don’t care about their problems” or “this is not a big problem, only some
>> ignorant want-to-be programmers have this problem” so why should anyone
>> care about them.
>>
>> It’s really a privilege for all who spend time on this level of software
>> construction and have the knowledge to understand all the details that are
>> discussed in this group and amongst people of this caliber of knowledge.
>> Declaring it somehow required and achievable by all, is problematic, and
>> that’s what I am continuing to stress.  Software doesn’t have to appear to
>> be magic.  The notion of least surprise (
>> https://en.wikipedia.org/wiki/Principle_of_least_astonishment) is an old
>> principle that has books written about it to try and illuminate the ideals
>> of how we should consider system design for the users of those systems.
>>
>> There are countless examples of how “training” is a requirement before
>> performing lots of tasks in jobs and in life in general.  It’s not the
>> training that I am complaining about.  It’s the notion that this single
>> optimization is something that breaks software systems in non-predictable
>> ways because it’s a large scale software system inspection, not a local,
>> recognizable optimization that the user somehow knows they purposefully
>> requested.
>>
>> I am go to once again cease here because I appear to be pushing buttons
>> with my conversation mode and I am really not trying to make people made or
>> defensive.  At some level these are hard discussions to have, I get that,
>> but I just really sense to much defensive posturing and so I really don’t
>> believe that the discussion can happen without creating even more walls to
>> have to figure out how to talk through.
>>
>> Gregg
>>
>> On Jul 20, 2021, at 5:41 AM, Andrew Dinn via Concurrency-interest <
>> [email protected]> wrote:
>>
>> On 19/07/2021 22:39, Gregg Wonderly via Concurrency-interest wrote:
>>
>> Thanks for you comments.   I am still trying to assert that the problem
>> is this kind of assumption about people writing the code, actually being
>> trained software engineers.  Instead, think of them as self taught coders.
>> People who only every wrote “basic” or “vb” style integrations with just
>> some knowledge that threads even exist, let alone, as in this case, knowing
>> that the AWT event queue is involved and that there are threads (or more in
>> the case of dialogs and other blocking actions) reaping events from the
>> queue and dispatching them into your code.  Even the term callback or
>> listener, for these people, doesn’t invoke any picture of “two” things
>> working together.
>>
>>
>> And I am still trying to assert that we should not hobble the language
>> implementation to cater for that category of 'programmer' (rabbit ears de
>> rigeur). Java has been specified and implemented for use by skilled and
>> knowledgeable professionals. That includes knowing about and having the
>> skill to deal with the presence of multi-threading as a core element of the
>> language, with all its attendant complexities.
>>
>> Of course, as a Java implementor I make no assumption that all those who
>> use Java will be skilled, knowledgeable professionals. What I do assume is
>> that I don't have to take the concerns or failings of unskilled or ignorant
>> 'would-be' coders into account.
>>
>> By the way, I believe you are having your cake and eating it in the way
>> you present your arguments here. You cited an example program as simple to
>> understand and behaving as expected until you remove some logging code to
>> simplify it and suddenly ... oh,. how surprising, a non-volatile access
>> gets hoisted! At which point this simple to understand code becomes
>> incomprehensible to the average reader.
>>
>> In truth, if you know how to read the different versions of this code
>> with an awareness that Java is a multi-threaded language the complexity is
>> never absent. The surprise you describe is prima facie evidence that your
>> posited average reader is not reading the code correctly, whether in the
>> original or reduced version. They just think they understand it.
>>
>> regards,
>>
>>
>> Andrew Dinn
>> -----------
>> Red Hat Distinguished Engineer
>> Red Hat UK Ltd
>> Registered in England and Wales under Company Registration No. 03798903
>> Directors: Michael Cunningham, Michael ("Mike") O'Neill
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [email protected]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [email protected]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
> _______________________________________________
> Concurrency-interest mailing list
> [email protected]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [email protected]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>

_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest