multithreadingthread-safetybuilderlombok

Is Lombok's builder thread safe?


I have a simple object

@Data
@Builder
public class Address {
    private Long id;
    private String street;
}

I make delombok of @Builder annotation and I see next code generated

@Data
public class Address {
    private Long id;
    private String street;

    @java.beans.ConstructorProperties({"id", "street"})
    Address(Long id, String street) {
        this.id = id;
        this.street = street;
    }

    public static AddressBuilder builder() {
       return new AddressBuilder();
    }

    public static class AddressBuilder {
        private Long id;
        private String street;

        AddressBuilder() {
        }

        public AddressBuilder id(Long id) {
            this.id = id;
            return this;
        }

        public AddressBuilder street(String street) {
            this.street = street;
            return this;
        }

        public Address build() {
            return new Address(id, street);
        }

        public String toString() {
            return "Address.AddressBuilder(id=" + this.id + ", street=" + this.street + ")";
        }
    }
}

Looking to this I see that builder is some static inner class of my Address class.

Let's imagine that I have 2 threads that uses builder executing in parallel.

First thread creates this local variable

Address address = Address.builder()
    .id(1L)
    .street("street 1")
    .build();

Second one creates this local one

Address address = Address.builder()
    .id(2L)
    .street("street 2")
    .build();

Looking to the implementation of lombok that uses static classes is it possible that running in parallel I'll have sometimes inside one of the threads an object id=1L street="street 2" or id=2L street="street 1"?


Solution

  • It is thread safe. In the method builder a new AddressBuilder object is created, so it is always working with a new object. The methods are only using local variables, no shared variables.

    To test this, I wrote the wollowing unit test:

    import com.anarsoft.vmlens.concurrent.junit.ConcurrentTestRunner;
    @RunWith(ConcurrentTestRunner.class)
    public class TestLombok {
    @Test
    public void testOne()
    {
        Address address = Address.builder()
                .id(1L)
                .street("street 1")
                .build();
    
    }
    @Test
    public void testTwo()
    {
        Address address = Address.builder()
                .id(2L)
                .street("street 2")
                .build();
    }   
    }
    

    with vmlens, a tool to detect race conditions, and it did not found as expected any races.

    The ConcurrentTestRunner used in the unit test is running the test method with 4 threads in parallel.