Безопасная публикация сценария производителя - PullRequest
0 голосов
/ 14 октября 2011

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

// effectively immutable
class SharedObject {

    private double data;

    public double getData() {
        return data;
    }

    public void setData(double data) {
        this.data = data;
    }
}

// object being shared between producent and consumers
class Holder {

    private volatile SharedObject sharedObject = new SharedObject();

    public SharedObject getSharedObject() {
        return sharedObject;
    }

    public void setSharedObject(SharedObject sharedObject) {
        this.sharedObject = sharedObject;
    }
}

class Producer extends TimerTask {

    private final Holder holder;

    public Producer(Holder holder) {
        this.holder = holder;
    }

    @Override
    public void run() {
        // produce new object
        SharedObject so = new SharedObject();
        so.setData(Math.random());
        // from now on 'so' object is effectively immutable

        // publish it
        holder.setSharedObject(so);
    }

}

class Consumer extends TimerTask {

    private Holder holder;

    public Consumer(Holder holder) {
        this.holder = holder;
    }

    @Override
    public void run() {
        // do something with the newest value - current snapshot (save, send etc.)
        System.out.println(holder.getSharedObject());
    }
}

public class Main {

    public static void main(String[] args) throws Exception {

        Holder holder = new Holder();

        Timer timer = new Timer();

        Producer producer = new Producer(holder);
        timer.scheduleAtFixedRate(producer, 0, 10);

        Consumer c1 = new Consumer(holder);
        timer.scheduleAtFixedRate(c1, 0, 10);

        Consumer c2 = new Consumer(holder);
        timer.scheduleAtFixedRate(c2, 0, 10);
    }
}

Идея основана на утверждении Java Concurrency на практике

Эффективно неизменяемые объекты должны быть безопасно опубликованы

1) Является ли это решение "безопасным" для моих нужд? (потребители смогут прочитать новейшее значение ссылки SharedObject и его данные внутри, значения могут быть потеряны между ними)

2) Знаете ли вы более оптимальные решения?

3) Если мы заботимся только о новейших снимках объекта, означает ли это, что у нас может быть несколько производителей?

Ответы [ 2 ]

0 голосов
/ 14 октября 2011
  1. Эта реализация в письменном виде реализует безопасную публикацию. причина, по которой это правда, из-за нестабильного магазина public void setSharedObject. Поскольку поле SharedObject является изменчивым, все пишет, что происходит до этого магазина будет виден после setSharedObject вызывается (это включает запись data).

    При этом, если производитель пишет SharedObject B и data b, а потребитель видит SharedObject A, он не видит data b. Хотя, если потребитель увидит SharedObject B, они гарантированы чтобы увидеть data b

  2. Volatile store - это около 1/3 общего времени магазина мониторов, так что я думаю это довольно быстро

Изменить, чтобы ответить на ваш вопрос:

Мне в основном нужно подтверждение, что "эффективно неизменяемые" объекты и все остальные внутренние поля в этих объектах, оба примитивы и другие ссылки, будут сразу видны. (при условии, что SharedObject и его внутренние компоненты никогда не будут изменены после издание).

Да, это правильно. Все записи, которые происходят в вызывающем потоке до того, как произойдет энергозависимая запись, будут видны любому вызывающему потоку, который видит эффект вступления в энергозависимую запись. Таким образом, если SharedObject видим, тогда данные SharedObject будут видны.

0 голосов
/ 14 октября 2011

Эффективно неизменяемые объекты должны быть безопасно опубликованы

SharedObject не является неизменным, поэтому не является безопасным.

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

class SharedObject {
    public final double data;
    SharedObject(double data) { this.data = data; }
}

Это гарантирует, что setData не может произойти ни до, ни после getData, поэтому нет необходимости распространять изменения в свойстве внутренних данных между потоками.

1) Является ли это решение "безопасным" для моих нужд? (потребители смогут прочитать новейшее значение ссылки SharedObject и его данные внутри, значения могут быть потеряны между ними)

volatile на общем объекте владельца должен означать, что holder.sharedObject всегда актуален при чтении.

3) Если мы заботимся только о новейших снимках объекта, означает ли это, что у нас может быть несколько производителей?

Слово «новейший» подразумевает некоторый смысл «случается раньше» - потребитель не видит производства ценностей, которые произошли до производства новейшей стоимости. Где это применяется?

EDIT:

Ok. Я думаю, что я понимаю проблему сейчас. Вы полагаетесь на volatile, чтобы представить не только правильный объект, но и правильный вид объекта. Это действительно в Java 5 и более поздних версиях, но не ранее.

С http://www.javamex.com/tutorials/synchronization_volatile_java_5.shtml

Начиная с Java 5, доступ к энергозависимой переменной создает барьер памяти: он эффективно синхронизирует все кэшированные копии переменных с основной памятью, как вход или выход из синхронизированного блока, который синхронизируется с данным объектом. Как правило, это не оказывает большого влияния на программиста, хотя иногда делает volatile хорошим вариантом для безопасной публикации объектов .

Таким образом, поскольку поле, содержащее ссылку на SharedObject, является изменчивым, потребитель всегда будет видеть самое последнее (для некоторого определения) значение, хранящееся в SharedObject.

Кажется, это соответствует требованиям, которые вы изложили.

Таким образом, в Java 4 и раньше это, вероятно, работало бы - до тех пор, пока SharedObject содержит поле из одного слова (не double с или long с), а в Java 5 и более поздних, где двойное слово проблема исправлена, вы солидны.

...