Synchronized classes have no public members

Jonathan M Davis via Digitalmars-d digitalmars-d at puremagic.com
Thu Oct 15 08:50:34 PDT 2015


On Thursday, 15 October 2015 at 15:16:59 UTC, Steven 
Schveighoffer wrote:
> I don't really understand all the disdain for synchronized 
> here...

Because it's usually either the wrong solution or just 
unnecessary. If you are going to have a single mutex for an 
entire object, then it's nice in the way that it's nice that 
invariants are nice. They're not at all necessary, because the 
same thing can be done manually via assertions inside of all of 
the public member functions, but it does make them less 
error-prone.

However, it's frequently the case that having a mutex per class 
object is the wrong way to go. Usually, it's better to have 
tighter locks than that which target specific member variables 
rather than the class as a whole, and when you do want it at the 
class level, it's frequently better to have the user of the class 
do the locking, since in that case, there's a decent chance that 
the object is a member variable inside of another class/struct 
where it and another set of variables need to share a mutex, so 
having a mutex built into the object is redundant and causes 
unnecessary overhead. Having the mutex at the class level is 
simply too inflexible and arguably encourages bad coding 
practices. So, having synchronized on classes or functions is of 
questionable value and arguably harmful - though the fact that 
having it on classes would allow us to strip away the outer layer 
of shared on the class' members does add some value.

Ultimately, the only advantages to synchronized classes IMHO are:

1. They makes porting Java code easier.
2. Similar to how invariant helps with assertions at the class 
level, they make it easier to use a mutex at the class level 
correctly (though IMHO, that's almost always the wrong design).
3. They give us a way to implicitly cast away shared on some 
level (though not necessarily enough to be worth it).

So, they add _some_ value, but I'm not at all convinced that 
they're worth it.

As for synchronized statements/blocks, they're simply syntactic 
sugar that add no real value that I can see, and they can do less 
then the equivalent with guards/autolocks. These two pieces of 
code are equivalent:

synchronized(mutex)
{
}

{
     Guard guard(mutex);
}

and the second one is far more flexible, since it allows for 
stuff like guard.unlock() or using the mutex with a condition 
variable. So, synchronized statements are a poor-man's 
guard/autolock and simply not worth having IMHO unless we find 
some way that it allows us to get the compiler to do stuff (like 
being able to implicitly remove shared on some level, though 
because you have arbitrary code within the synchronized block and 
aren't dealing with encapsulated shared variables like with 
synchronized classes, I don't see how we really can get the 
compiler to do much special with synchronized blocks).

I don't know that it's worth it to remove synchronized from the 
language, but certainly, if we were starting from scratch, I'd be 
arguing against it. I think that it's a Java-ism that shouldn't 
have been ported to D. Java and C# had no choice, because they 
don't have proper RAII or scope statements, but we don't have 
that problem.

- Jonathan M Davis


More information about the Digitalmars-d mailing list