Synchronized blocks in value constructors
-
liangchenblue at gmail.com
Mon Sep 25 09:37:57 UTC 2023
Honestly, I don't understand why you propose this, for synchronized is
ALREADY the default behavior of Value Classes per JEP 401. By default, all
fields in a value class are synchronized (non-atomic), so you won't see a
Range where min > max. The current proposed syntax asks users to opt-in
into non-atomic (or non-synchronized in your words) for being non-atomic is
bug-prone.
Chen Liang
On Mon, Sep 25, 2023 at 5:01 PM João Mendonça <jf.mend at gmail.com> wrote:
> Hello Chen,
>
>
> Thank you very much for your response.
> To address the fragility issue you raised, I would modify the new syntax
> proposal to:
>
> *** synchronized blocks in value class field declarations. ***
>
> To your very good point on granularity, I think that synchronized blocks
> could still be considered more readable than having to segregate fields in
> separate value classes and using some other class modifier/keyword to
> indicate non-atomicity.
> All the other advantages/disadvantages would remain the same.
> Your example would become:
>
> value class Container {
> synchronized {int a, b;}
> int c;
> Container(int a, int b, int c) {
> this.a = a;
> this.b = b;
> this.c = c;
> }
> }
>
>
> João Mendonça
>
>
> On Mon, Sep 25, 2023 at 2:08 AM - <liangchenblue at gmail.com> wrote:
>
>> Hello Joao,
>> I believe the synchronized block proposal is fragile and isn't a good
>> hint to the VM. Each constructor can declare its own synchronization
>> groups, which makes behaviorally-correct optimization harder.
>> For your purpose where you only need to declare some of the properties of
>> the value class atomically together, you can group those properties in an
>> atomic (regular) value class. Then, you can include these regular value
>> classes in a non-atomic value class.
>>
>> Say you have this:
>> value class Container {
>> int a, b, c;
>> Container(int a, int b, int c) {
>> synchronized { this.a = a; this.b = b; }
>> this.c = c;
>> }
>> }
>>
>> Why not this instead:
>> nonatomic value class Container {
>> value class Constraint {
>> int a, b;
>> Constraint(int a, int b) { this.a = a; this.b = b; }
>> }
>> Constraint ab; int c;
>> Container(int a, int b, int c) {
>> this.ab = new Constraint(a, b);
>> this.c = c;
>> }
>> }
>>
>> Chen Liang
>>
>> On Mon, Sep 25, 2023 at 8:58 AM João Mendonça <jf.mend at gmail.com> wrote:
>>
>>> I would like to propose a new syntax to specify that, in a value class,
>>> some fields must be assigned atomically together:
>>>
>>> *** synchronized blocks in value class constructors. ***
>>>
>>>
>>> Advantages:
>>>
>>> - granularity - only the specific fields involved in an invariant
>>> need to be assigned in the same synchronized block. Multiple blocks can be
>>> used for independent invariants. Tearing is allowed between blocks and
>>> between fields assigned outside blocks. VMs could take advantage of this to
>>> perform optimizations.
>>> - economy - no new keyword/annotation/interface needed.
>>> - compatibility - synchronized blocks are currently illegal in
>>> constructors.
>>> - safety - just like with identity classes, the absence of a
>>> synchronized block in a constructor means that the whole constructor is
>>> synchronized, i.e. all fields are written atomically.
>>> - safety - an empty synchronized block is required to indicate that
>>> tearing is allowed between any fields.
>>> - clarity - "A synchronized block of field assignments" is a very
>>> intuitive description of the semantics involved, given the meaning of the
>>> word "synchronized" in english.
>>>
>>>
>>> Disadvantages:
>>>
>>> - aesthetics - an empty synchronized block is required to indicate
>>> that tearing is allowed between any fields.
>>> - safety - a user of a value class has no automatic way to be
>>> informed of if/where tearing may occur (can be fixed with an update to
>>> the generation of java docs).
>>> - clarity - synchronized blocks (§14.18.) have two meanings:
>>> - The old meaning in regular methods: only one thread may be
>>> running inside of a block for the object given in the expression clause
>>> - The new meaning in constructors: all assignments in a block
>>> are written atomically (no expression clause)
>>>
>>> Example:
>>>
>>> value class Range {
>>> long start, end;
>>> public Range(long start, long end) {
>>> if (start > end) throw new IllegalArgumentException();
>>> synchronized {
>>> this.start = start;
>>> this.end = end;
>>> }
>>> } }
>>>
>>> Having all fields assigned in the same synchronized block, as above, is equivalent to declaring no synchronized blocks:
>>>
>>> value class Range {
>>> long start, end;
>>>
>>> public Range(long start, long end) {
>>> if (start > end) throw new IllegalArgumentException();
>>> this.start = start;
>>> this.end = end;
>>> } }
>>>
>>>
>>> Another example:
>>>
>>> value class Point {
>>> double x, y;
>>> public Point(double x, double y) {
>>> synchronized {}
>>> this.x = x; this.y = y;
>>> } }
>>>
>>>
>>>
>>> João Mendonça
>>>
>>>
>
> On Mon, Sep 25, 2023 at 2:08 AM - <liangchenblue at gmail.com> wrote:
>
>> Hello Joao,
>> I believe the synchronized block proposal is fragile and isn't a good
>> hint to the VM. Each constructor can declare its own synchronization
>> groups, which makes behaviorally-correct optimization harder.
>> For your purpose where you only need to declare some of the properties of
>> the value class atomically together, you can group those properties in an
>> atomic (regular) value class. Then, you can include these regular value
>> classes in a non-atomic value class.
>>
>> Say you have this:
>> value class Container {
>> int a, b, c;
>> Container(int a, int b, int c) {
>> synchronized { this.a = a; this.b = b; }
>> this.c = c;
>> }
>> }
>>
>> Why not this instead:
>> nonatomic value class Container {
>> value class Constraint {
>> int a, b;
>> Constraint(int a, int b) { this.a = a; this.b = b; }
>> }
>> Constraint ab; int c;
>> Container(int a, int b, int c) {
>> this.ab = new Constraint(a, b);
>> this.c = c;
>> }
>> }
>>
>> Chen Liang
>>
>> On Mon, Sep 25, 2023 at 8:58 AM João Mendonça <jf.mend at gmail.com> wrote:
>>
>>> I would like to propose a new syntax to specify that, in a value class,
>>> some fields must be assigned atomically together:
>>>
>>> *** synchronized blocks in value class constructors. ***
>>>
>>>
>>> Advantages:
>>>
>>> - granularity - only the specific fields involved in an invariant
>>> need to be assigned in the same synchronized block. Multiple blocks can be
>>> used for independent invariants. Tearing is allowed between blocks and
>>> between fields assigned outside blocks. VMs could take advantage of this to
>>> perform optimizations.
>>> - economy - no new keyword/annotation/interface needed.
>>> - compatibility - synchronized blocks are currently illegal in
>>> constructors.
>>> - safety - just like with identity classes, the absence of a
>>> synchronized block in a constructor means that the whole constructor is
>>> synchronized, i.e. all fields are written atomically.
>>> - safety - an empty synchronized block is required to indicate that
>>> tearing is allowed between any fields.
>>> - clarity - "A synchronized block of field assignments" is a very
>>> intuitive description of the semantics involved, given the meaning of the
>>> word "synchronized" in english.
>>>
>>>
>>> Disadvantages:
>>>
>>> - aesthetics - an empty synchronized block is required to indicate
>>> that tearing is allowed between any fields.
>>> - safety - a user of a value class has no automatic way to be
>>> informed of if/where tearing may occur (can be fixed with an update to
>>> the generation of java docs).
>>> - clarity - synchronized blocks (§14.18.) have two meanings:
>>> - The old meaning in regular methods: only one thread may be
>>> running inside of a block for the object given in the expression clause
>>> - The new meaning in constructors: all assignments in a block
>>> are written atomically (no expression clause)
>>>
>>> Example:
>>>
>>> value class Range {
>>> long start, end;
>>> public Range(long start, long end) {
>>> if (start > end) throw new IllegalArgumentException();
>>> synchronized {
>>> this.start = start;
>>> this.end = end;
>>> }
>>> } }
>>>
>>> Having all fields assigned in the same synchronized block, as above, is equivalent to declaring no synchronized blocks:
>>>
>>> value class Range {
>>> long start, end;
>>>
>>> public Range(long start, long end) {
>>> if (start > end) throw new IllegalArgumentException();
>>> this.start = start;
>>> this.end = end;
>>> } }
>>>
>>>
>>> Another example:
>>>
>>> value class Point {
>>> double x, y;
>>> public Point(double x, double y) {
>>> synchronized {}
>>> this.x = x; this.y = y;
>>> } }
>>>
>>>
>>>
>>> João Mendonça
>>>
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20230925/14ca3e12/attachment-0001.htm>
More information about the valhalla-spec-observers
mailing list