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