Потокобезопасность статического вложенного класса — Java

У меня есть статический класс «Builder» внутри класса «MyClass». Если я попытаюсь создать два экземпляра MyClass с помощью конструктора одновременно из двух потоков, будет ли это безопасно? Могут ли значения, установленные одним потоком, быть присвоены объекту, созданному другим потоком?

Код:

public class MyClass {
    private int height;
    private int weight;

    private MyClass(Builder builder) {
        height = builder.height;
        weight = builder.weight;
    }

    public static class Builder {
        private int height;
        private int weight;

        public Builder height(int h) {
            height = h;
            return this;
        }

        public Builder weight(int w) {
            weight = w;
            return this;
        }

        public MyClass build() {
            return new MyClass(this);
        }

    }
}

person shadowfax    schedule 05.07.2014    source источник
comment
Почему вы думаете, что это может быть небезопасно?   -  person Oliver Charlesworth    schedule 05.07.2014
comment
Здравствуйте, Shadow, как вы собираетесь использовать свой конструктор (пожалуйста, предоставьте пример кода)?   -  person Anthony Accioly    schedule 05.07.2014
comment
Статический внутренний класс не является статическим в том смысле, что он является формой синглтона, это просто означает, что он по существу является классом верхнего уровня и не может неявно обращаться к методам и полям в охватывающем типе.   -  person Mark W    schedule 05.07.2014


Ответы (2)


Если я попытаюсь создать два экземпляра MyClass с помощью конструктора одновременно из двух потоков, будет ли это безопасно?

Если вы имеете в виду использование одного и того же экземпляра Builder в обоих потоках, то нет, но если каждый поток имеет свой собственный экземпляр Builder, тогда все будет в порядке. С таким узором:

MyClass c = new MyClass.Builder().height(10).weight(2).build();

каждый экземпляр Builder является локальным для одного потока.

person Ian Roberts    schedule 05.07.2014

Я вижу, ты получил ответ. Просто чтобы добавить к этому, конечно, строитель не является потокобезопасным. В текущей форме вашего кода изменение следующего может сделать это так.

public static class Builder {
    private volatile int height;
    private volatile int weight;
person ac3    schedule 05.07.2014
comment
Ему нужны два экземпляра в разных стеках потоков, в этой ситуации нет необходимости в volatile. - person Mark W; 05.07.2014
comment
Нет, если два экземпляра созданы из одного и того же экземпляра билдера, он ему понадобится. Я думал, что это был вопрос - иначе ему не было бы смысла даже говорить о потокобезопасности - person ac3; 05.07.2014
comment
Нет, если два экземпляра созданы из одного и того же экземпляра построителя - это ерунда, volatile требуется только в том случае, если два потока будут совместно использовать экземпляр, в его случае они не будут. Он думал, что статический внутренний класс статичен в том смысле, что он сделает Builder одноэлементным. - person Mark W; 05.07.2014
comment
Если вы перечитаете, я сказал тот же «экземпляр строителя». С тем же экземпляром сборщика, если вы не видите проблемы с потоками, это ваша проблема. Что касается того, что он думал/думает, я не претендую на какие-либо ноу-хау по этому поводу - просто сказал, что со статическим внутренним классом не может быть и речи о какой-либо потокобезопасности - это довольно просто - person ac3; 05.07.2014
comment
это своего рода проблема x/y здесь. Конечно, ответ на заданный вопрос правильный, но, учитывая то, как вы будете использовать экземпляр построителя, эта проблема просто не возникает (почти по той же причине, по которой использование StringBuilder доминирует над StringBuilder на 10000: 1). - person Voo; 06.07.2014
comment
Могу ли я предположить, что вы имели в виду StringBuilder вместо StringBuffer? И да, мой ответ был только на первоначально заданный вопрос: могут ли значения, установленные одним потоком, быть присвоены объекту, созданному другим потоком? может означать только использование одного и того же «экземпляра построителя» для установки значения в одном потоке и создания объекта в другом. Я просто сказал «нет» и попытался сделать что-то, что могло бы заставить ответить «да». - person ac3; 06.07.2014