Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

further improvement of Lazy.get() #1571

Merged
merged 1 commit into from Sep 18, 2016
Merged

further improvement of Lazy.get() #1571

merged 1 commit into from Sep 18, 2016

Conversation

danieldietrich
Copy link
Member

thx @jbgi for the hint!

@codecov-io
Copy link

codecov-io commented Sep 17, 2016

Current coverage is 96.98% (diff: 100%)

Merging #1571 into master will increase coverage by <.01%

@@             master      #1571   diff @@
==========================================
  Files            88         88          
  Lines         10642      10642          
  Methods           0          0          
  Messages          0          0          
  Branches       1813       1813          
==========================================
+ Hits          10320      10321     +1   
  Misses          179        179          
+ Partials        143        142     -1   

Powered by Codecov. Last update 63e7872...3b8171e

@@ -133,12 +135,13 @@ private Lazy(Supplier<? extends T> supplier) {
*/
@Override
public T get() {
// using a local var speeds up the double-check idiom by 25%, see Effective Java, Item 71
Supplier<? extends T> tmp = supplier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I strongly think we should base speedups on JMH benchmarks, our intuition is most often wrong about these ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will create a (local) benchmark and post the results...

Supplier<? extends T> tmp = supplier;
if (tmp != null) {
synchronized (this) {
tmp = supplier;
if (tmp != null) {
value = supplier.get();
value = tmp.get();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please rename tmp to something meaningful?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reads of volatile variables need to access the main memory to ensure the value is actual. tmp could be named cachedSupplier or localSupplier.

Because we return value instead of supplier, we do not need to cache the supplier before entering the synchronized block.

Within the synchronized block we have two reads (1. not-null check, 2. get() call). So a changed supplier saves one main-memory read.

The optimized code then looks like this:

public T get() {
    if (this.supplier != null) {
        synchronized (this) {
            // only one volatile read from main-memory
            final Supplier<? extends T> supplier = this.supplier;
            if (supplier != null) {
                value = supplier.get();
                this.supplier = null; // free mem
            }
        }
    }
    return value;
}

@@ -133,12 +135,13 @@ private Lazy(Supplier<? extends T> supplier) {
*/
@Override
public T get() {
// using a local var speeds up the double-check idiom by 25%, see Effective Java, Item 71
Copy link
Contributor

@paplorinc paplorinc Sep 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment if for review only, I don't think it should stay in the code.
25%, based on what?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that we should remove the speed-up comment.

However, it is hard to recognize design patterns/idioms when looking at code. Code is just a textual projection of abstract ideas (very much like 3D to 2D/Screen projection).

I want a comment for developers why we added a local var instead of using the well-known classical double-check idiom.

@danieldietrich danieldietrich merged commit 56d8934 into vavr-io:master Sep 18, 2016
@danieldietrich
Copy link
Member Author

Aargh, sorry @paplorinc. I've overseen the comments. Will apply your comments soon and send a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants