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