Thread overview
an extremely naive question regarding synchronized...
Nov 14, 2016
WhatMeWorry
Nov 15, 2016
Kapps
Nov 16, 2016
Kagamin
November 14, 2016
I was reading this fasciniating article:

https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/

And to quote a section of it:
-----------------------------------------------------
static MySingleton get() {
    synchronized {
      if (instance_ is null) {
        instance_ = new MySingleton;
      }
    }
    return instance_;
  }

Now, if Thread 1 calls get(), it has a chance to finish instantiating instance_ and storing a reference to it before Thread 2 checks whether instance_ is null.  There’s only one problem with this:  It comes at a huge performance cost (benchmarks forthcoming).  Entering a synchronized block is expensive.
-----------------------------------------------------

Why is the synchronized block so expensive?  Isn't it just doing one conditional and a new command?  Again, to my naive way of thinking, this seems like a very small blocking window.

And the graph shows 1B get() calls.  I assume B stands for billion.  What use case would require so many gets?

Thanks.






November 14, 2016
On 11/14/16 12:43 PM, WhatMeWorry wrote:
>
> I was reading this fasciniating article:
>
> https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/
>
> And to quote a section of it:
> -----------------------------------------------------
> static MySingleton get() {
>     synchronized {
>       if (instance_ is null) {
>         instance_ = new MySingleton;
>       }
>     }
>     return instance_;
>   }
>
> Now, if Thread 1 calls get(), it has a chance to finish instantiating
> instance_ and storing a reference to it before Thread 2 checks whether
> instance_ is null.  There’s only one problem with this:  It comes at a
> huge performance cost (benchmarks forthcoming).  Entering a synchronized
> block is expensive.
> -----------------------------------------------------
>
> Why is the synchronized block so expensive?  Isn't it just doing one
> conditional and a new command?  Again, to my naive way of thinking, this
> seems like a very small blocking window.

It's expensive when compared to simply reading a piece of memory.

synchronized means that the CPU core has to sync it's view of memory with the memory manager and all the other CPUs in the system.

> And the graph shows 1B get() calls.  I assume B stands for billion.
> What use case would require so many gets?

This is a typical technique with benchmarking to show some measurable results. If it had, say 10 gets, the noise of context switching, or of different various things running in the OS could sway the graph a huge amount. Not to mention that time measurement on an OS is in discrete units that may not even capture the short time to do 10 gets.

In other words, if your stopwatch only has a second hand, and it takes 1 ms to do something, you need to repeat that thing 10,000 times in order to properly measure it.

-Steve
November 15, 2016
On Monday, 14 November 2016 at 17:43:37 UTC, WhatMeWorry wrote:
>
> I was reading this fasciniating article:
>
> https://davesdprogramming.wordpress.com/2013/05/06/low-lock-singletons/
>
> And to quote a section of it:
> -----------------------------------------------------
> static MySingleton get() {
>     synchronized {
>       if (instance_ is null) {
>         instance_ = new MySingleton;
>       }
>     }
>     return instance_;
>   }
>
> Now, if Thread 1 calls get(), it has a chance to finish instantiating instance_ and storing a reference to it before Thread 2 checks whether instance_ is null.  There’s only one problem with this:  It comes at a huge performance cost (benchmarks forthcoming).  Entering a synchronized block is expensive.
> -----------------------------------------------------
>
> Why is the synchronized block so expensive?  Isn't it just doing one conditional and a new command?  Again, to my naive way of thinking, this seems like a very small blocking window.
>
> And the graph shows 1B get() calls.  I assume B stands for billion.  What use case would require so many gets?
>
> Thanks.

Keep in mind, this is only slow for such a large amount of calls.
If you're calling this only a hundred times a second, then who cares if it's slower. After all, with GDC we were looking at 1 billion calls in 21 seconds. That's 47,000 calls per *millisecond*.
November 15, 2016
On 11/15/16 3:05 PM, Kapps wrote:

>
> Keep in mind, this is only slow for such a large amount of calls.
> If you're calling this only a hundred times a second, then who cares if
> it's slower. After all, with GDC we were looking at 1 billion calls in
> 21 seconds. That's 47,000 calls per *millisecond*.

This is the wrong way to look at it.

If you are calling it from one thread, then 100 times/second is no problem. If you have 100 threads calling it 100 times a second, you have killed any performance gained by using threads in the first place.

The reason lock-free singletons are so attractive is because of the allowance of multiple threads to use it at the same time without contention. It's why years of "slightly wrong" advice on singletons has been out there, and why this solution is so amazing in its simplicity.

-Steve
November 16, 2016
  static MySingleton get() {
    if (instance_ is null) {
      synchronized {
        if (instance_ is null) {
          atomicStore(instance_, new MySingleton);
        }
      }
    }
    return instance_;
  }

This should work fine and faster.