0

我对多线程和使用设计模式都是新手。

我有一些线程使用显式多线程,如果任何线程都没有计算过某个数字的阶乘,那么每个线程都应该计算它。我为此使用享元模式。

    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,我想是的。

任何其他做我想做的事情的方式也将受到高度赞赏。

4

1 回答 1

1

你可能有几个目标。做什么取决于你想要做什么。

因此,在这种情况下,您似乎试图避免重复计算,但这种计算并不是特别昂贵。您可能会遇到锁争用问题。因此,要使其线程安全使用ThreadLocal<Map<String, Fact>>. 可能InheritableThreadLocal<Map<String, Fact>>在哪里childValue复制Map.

通常有一组已知的可能很常见的值,而您只需要这些值。在这种情况下,在类静态初始化期间计算一个Map(或数组)。

如果您希望享元在线程之间共享并且是唯一的,ConcurrentHashMap请与Map.computeIfAbsent方法一起使用。

如果您希望享元在线程之间共享,并且是唯一的,并且您希望确保只进行一次计算,那么它会变得更加困难。您需要将(如果不存在)占位符放入ConcurrentMap; 如果当前线程获胜,则将其替换为计算值并通知,否则等待计算。

现在,如果您希望对享元进行垃圾收集,您将需要WeakHashMap. 这不可能是ConcurrentMap使用 Java SE 集合,这使得它有点绝望。您可以使用良好的老式锁定。或者,该值可以是 a WeakReference<Fact>,但您需要自己管理驱逐。

可能Fact只是间歇性地保留对的强引用,但您不希望过于频繁地重新创建它,在这种情况下,您将需要SoftReference而不是WeakReference. Indeed的WeakHashMap表现令人惊讶,在某些情况下会导致性能在之前正常工作后下降到无法使用。

(请注意,在这种情况下,您Map会更好地键入Integer。)

于 2019-11-10T13:51:59.530 回答