4 ms·
> Identity hashcodes and monitors are perennially tricky to implement with low space overhead and I think in hindsight that putting them at the base of the obje
by Someone 4y ago
> Identity hashcodes and monitors are perennially tricky to implement with low space overhead and I think in hindsight that putting them at the base of the object model (i.e. every object has them) was a mistake.
I can understand the hashcode choice, but I never understood why they chose to add the ability to lock on any object. IMO it still is a bad choice now on server machines, and it certainly was in a language designed for embedded devices in the early 1990s.
Does anybody know what they were thinking? Were they afraid of having to support parallel class hierarchies with a LockableFoo alongside Foo for every class? If so, why? Or did they think most programs would have very few objects, and mostly use reference types?
- paulddraper 4y ago> Does anybody know what they were thinking? Ergonomics. (Plus an inherent assumption of mutable data.) You can write `synchronized (this)` or `synchronized` class method, etc. and it just works.
- derefr 4y agoIf I were the Java1.0 authors, I probably would have: - made a "monitor slot" its own primitive type; - made two overloads of `synchronized` — synchronized(MonitorSlot), and synchronized(Object); where for synchronized(Object), the compiler expects to find a MonitorSlot-typed field with a special system name (e.g. "__jvmMonitorSlot") on the passed-in Object - taken the presence of `synchronized (this)` in body code of a class to implicitly define such a field on the class, meaning you can "just write" `synchronized (this)`, since it becomes `synchronized (this.__jvmMonitorSlot)` and also triggers the creation of the __jvmMonitorSlot field - explicitly define the __jvmMonitorSlot field on Class and other low-object-count system types The only change from today would be that you can't point at some arbitrary Object you didn't define the class for yourself, and say "synchronize on that." Which... why do you want to be doing that again?
- paulddraper 4y agoYes with sufficient complexity, it's possible to achieve transparently the same result.
- titzer 4y agoFor me, the main question is where this complexity lives. To minimize the places where sharp knives need to be used, I would prefer to move this up into a language runtime and have the VM/engine underneath focus on implementing a simpler object model that has the mechanisms to pull off these tricks without resorting to unsafe tricks.
- ShroudedNight 4y agoAt that point, why not just make types you want lock functionality for be declared as 'synchronized' in their class definition: synchronized class Foo { //... }
- derefr 4y agoBecause, for the things that do care about synchronization, they might want multiple explicit MonitorSlot members. It makes more sense to just be able to synchronize on MonitorSlots directly, and then decide where they go. The only reason I added the `synchronized (this)` allowance was because the parent said that they think that that's "good ergonomics" — and presumably, the Java1.0 authors also thought that — and I was trying to suggest an alternative that would preserve what they consider "good ergonomics." But personally, if I was the sole dictator of Java1.0 language design with nobody else to please, I would just have `synchronize(MonitorSlot)` + explicitly-defined MonitorSlot members (that, if you declare one, must always be declared final, and cannot be assigned to in the constructor), and that's it. Just refer to them by name when you need one.
- usrusr 4y agoYou underestimate the weight of that little "(Plus an inherent assumption of mutable data.)" side note in pauldraper's post: that one is really huge and the concise form of his post doesn't really do justice to how clearly it answers the entire sub-thread. Java was driven by the admission that multithreading is hard, and the hybris that this hard problem would go away once and for all if only you added enough OOP state hiding and locks. All those strategies we now use to allow parallelism were either unknown back then, or unfashionable, because they were in conflict with that OOP dream world of "objects talking to each other". The ease of just writing synchronized everywhere and declaring done on the topic of multithreading was as much a selling point of early Java as memory safety.
- Someone 4y agoYes, but the number of things you want to synchronize on in real-life code is limited, and, certainly at the time, memory was scarce. I think only allowing ‘synchronized’ on containers and allowing programmers to opt-in on them would have been the better choice. > Plus an inherent assumption of mutable data. Yet, Strings and the boxed value types (Integer, Long, etc.) are immutable, and you can synchronize on them (or does this matter less for those because of the granularity of the memory allocator?)
- paulddraper 4y ago> Strings and the boxed value types (Integer, Long, etc.) are immutable, and you can synchronize on them Side note: That is a very bad idea, because their object identity is iffy.
- deleted 4y ago[deleted]
- mike_hearn 4y agoAt the time, there was a widespread assumption that massively parallel computing was the future and thus that any serious language had to try and integrate concurrency as a core feature. It wasn't just Java. For many years THE argument for functional languages was you'd better learn them because these languages will soon be automatically parallelized, and that's the only way you'll be able to master machines with thousands of cores. With hindsight we know it didn't work out like that. We got multi-core CPUs but not that many cores. Most code is still single threaded. We got SIMD but very little code uses it. We got GPUs with many cores, but they are programmed with imperative fairly boring C-like languages that don't use locking or message passing or anything else, they're data parallel pure functions. But at the time, people didn't know that. You can see how in that environment of uncertainty "everything will be massively multi-threaded so let's give everything a lock" might have made sense
- paulddraper 4y ago> We got SIMD but very little code uses it. Because programming for SIMD is wildly different than MIMD. (And MIMD is what `synchronized` is for.) The theory was that there would be more machines like AMD Thread Ripper.