Используя потоки и шаблон Flyweight вместе в Java? - PullRequest
0 голосов
/ 10 ноября 2019

Я новичок как в многопоточности, так и в использовании шаблонов проектирования.

У меня есть несколько потоков, использующих явную многопоточность, и каждый из них предполагает вычисление факториала числа, если оно не быловычисляется когда-либо любым потоком. Для этого я использую Flyweight Pattern.

    private final long Comp;
    private static Map<String, Fact> instances=new HashMap<String, Fact>();

    private Fact(long comp) {
        Comp=comp;
    }

    public static Fact getInstance(int num){
        String key=String.valueOf(num);
        if(!instances.containsKey(key)){
            int comp=//calculate factorial of num
            instances.put(key, new Fact(comp));
        }
        return instances.get(key);
    }

    public long get_Comp(){
        return this.Comp;
    }
}
public class Th implements Runnable {
    // code elited
    @Override
    public void run() {
        //get number and check if it's already in the HashMap, if no, 
          compute
    }

}

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

Если я добавлю вычисления в классе Fact (Flyweight), то останется ли он в Flyweight, я думаю, да.

Любой другой способ сделать то, что я хочу, также будет высоко оценен.

1 Ответ

0 голосов
/ 10 ноября 2019

У вас есть пара целей. Что делать, зависит от того, что вы пытаетесь сделать.

Так что в этом случае вы пытаетесь избежать повторных вычислений, но эти вычисления не особенно дороги. Вы можете столкнуться с проблемой конкуренции за блокировку. Поэтому, чтобы сделать его потокобезопасным, используйте ThreadLocal<Map<String, Fact>>. Потенциально InheritableThreadLocal<Map<String, Fact>>, где childValue копирует Map.

. Часто существует известный набор значений, которые могут быть общими, и вы просто хотите их получить. В этом случае вычислите Map (или массив) во время статической инициализации класса.

Если вы хотите, чтобы маховики были распределены между потоками и были уникальными, используйте ConcurrentHashMap with вместе с методом Map.computeIfAbsent.

Если вы хотите, чтобы маховики распределялись между потоками, были уникальными, и вы хотели бы убедиться, что вы выполняете вычисления только один раз, это становится немного сложнее. Вы должны поместить (если отсутствует) заполнитель в ConcurrentMap;если текущий поток выигрывает, замените его на вычисленное значение и сообщите, в противном случае дождитесь вычисления.

Теперь, если вы хотите, чтобы маховики собирались мусором, вы бы хотели WeakHashMap. Это не может быть ConcurrentMap с использованием коллекций Java SE, что делает его немного безнадежным. Вы можете использовать старый добрый замок. В качестве альтернативы значение может быть WeakReference<Fact>, но вам нужно самостоятельно управлять выселением.

Возможно, сильная ссылка на Fact сохраняется только периодически, но вы не хотите, чтобы она былавоссоздается слишком часто, и в этом случае вам понадобится SoftReference вместо WeakReference. Действительно, WeakHashMap может вести себя , что на удивление , в некоторых случаях приводя к падению производительности до непригодного после ранее работающей безупречной работы.

(Обратите внимание, в этом случае ваш Mapбыло бы лучше набрать Integer.)

...