Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何修改类设计以使其线程安全_Java_Multithreading_Concurrency_Thread Safety - Fatal编程技术网

Java 如何修改类设计以使其线程安全

Java 如何修改类设计以使其线程安全,java,multithreading,concurrency,thread-safety,Java,Multithreading,Concurrency,Thread Safety,我在想,我的设计可能会让我陷入一种无法保证线程安全的境地。如果是这样的话,有人可能会提供一些建议来改变这种情况吗 我有一个代表当前投标人的类 public final class Bidders { private static volatile ConcurrentMap<String, BidValue> bidders = new ConcurrentHashMap<String, BidValue>(); public Bidders(Conc

我在想,我的设计可能会让我陷入一种无法保证线程安全的境地。如果是这样的话,有人可能会提供一些建议来改变这种情况吗

我有一个代表当前投标人的类

public final class Bidders {

    private static volatile ConcurrentMap<String, BidValue> bidders = new ConcurrentHashMap<String, BidValue>();

    public Bidders(ConcurrentMap<String, BidValue currentBidders){
        if(bidders != null){
            bidders = currentBidders;
        }
    }

    public static synchronized ConcurrentMap<String, BidValue> getBidders(){
        return bidders;
    }

    public static synchronized void updateBidder(String bidderName, BidValue value){
        if(value != null){
            bidders.put(bidderName, value);
        }
    }
}
例如,我可以预见,使用updatebidder可能会对映射进行修改,而getBidders可能会在完成之前被调用,从而留下不一致的状态。但是,我需要通过我的应用程序访问此状态以进行各种更新

是否有人可以建议我如何以不同的方式/以更好的方式来实现这一点,例如,列举一些我可以研究的技术,以帮助我构建更健壮的应用程序

谢谢

对映射的修改可能会使用updatebidder进行,并且可能会在映射完成之前调用getBidders,从而留下不一致的状态

您使用的是ConcurrentMap,它是为应对这些情况而构建的

静态的使用,在构造函数中注入映射,返回映射,都是巨大的代码气味,但是我不明白为什么你要从发布的有限代码中执行这些操作。我的投标人会这样开始,这是threadsafe,原因在评论中:

public final class Bidders {

    // I don't need a concurrent map any longer, I'm in control of the concurrency within
    // this class.
    private final Map<String, BidValue> bidders = new HashMap<String, BidValue>();

    public void updateBidder(String bidderName, BidValue value) {
        if (value != null) {
            synchronized (this) {
                // ensures we do not add while we're enumerating
                bidders.put(bidderName, value);
            }
        }
    }

    public List<PlayerBid> getBids() {
        List<PlayerBid> bids = new ArrayList<PlayerBid>();
        synchronized (this) {
            // ensures we do not add while we're enumerating,
            // if we returned the map
            // we couldn't guarantee this would happen.
            for (Entry<String, BidValue> entry : bidders.entrySet()) {
                bids.add(new PlayerBid(entry.getKey(), entry.getValue()));
            }
        }
        return bids;
    }

    // add other methods as you need, but avoid returning the internals of
    // this class
}
用法:

Bidders.INSTANCE.updateBidder(...);
对映射的修改可能会使用updatebidder进行,并且可能会在映射完成之前调用getBidders,从而留下不一致的状态

您使用的是ConcurrentMap,它是为应对这些情况而构建的

静态的使用,在构造函数中注入映射,返回映射,都是巨大的代码气味,但是我不明白为什么你要从发布的有限代码中执行这些操作。我的投标人会这样开始,这是threadsafe,原因在评论中:

public final class Bidders {

    // I don't need a concurrent map any longer, I'm in control of the concurrency within
    // this class.
    private final Map<String, BidValue> bidders = new HashMap<String, BidValue>();

    public void updateBidder(String bidderName, BidValue value) {
        if (value != null) {
            synchronized (this) {
                // ensures we do not add while we're enumerating
                bidders.put(bidderName, value);
            }
        }
    }

    public List<PlayerBid> getBids() {
        List<PlayerBid> bids = new ArrayList<PlayerBid>();
        synchronized (this) {
            // ensures we do not add while we're enumerating,
            // if we returned the map
            // we couldn't guarantee this would happen.
            for (Entry<String, BidValue> entry : bidders.entrySet()) {
                bids.add(new PlayerBid(entry.getKey(), entry.getValue()));
            }
        }
        return bids;
    }

    // add other methods as you need, but avoid returning the internals of
    // this class
}
用法:

Bidders.INSTANCE.updateBidder(...);

你要小心你正在采取的方法。您只不过是将一个已经是线程保存的对象包装起来,并由此产生一种错觉,即您的应用程序变得线程安全。你真的应该看看你的“业务逻辑”,并使线程安全。公开ConcurrentHashMap实际上会破坏线程安全

因此,请研究一种从如下界面开始的方法:

public interface BidManager {
    void registerBid (String bidderName, BidValue bidValue);

    void stopBids();

    boolean hasBid(String bidderName);

    void calculateWinningBid();

    String getWinnnigBidderName();

    BidValue getWinningBidValue();

}

然后从这里开始工作,首先确保您可以以线程安全的方式实现此接口,然后设置一种以线程安全的方式获取这些BidManager对象的方法,可以使用单例模式,也可以通过其他方式

你要小心你正在采取的方法。您只不过是将一个已经是线程保存的对象包装起来,并由此产生一种错觉,即您的应用程序变得线程安全。你真的应该看看你的“业务逻辑”,并使线程安全。公开ConcurrentHashMap实际上会破坏线程安全

因此,请研究一种从如下界面开始的方法:

public interface BidManager {
    void registerBid (String bidderName, BidValue bidValue);

    void stopBids();

    boolean hasBid(String bidderName);

    void calculateWinningBid();

    String getWinnnigBidderName();

    BidValue getWinningBidValue();

}

然后从这里开始工作,首先确保您可以以线程安全的方式实现此接口,然后设置一种以线程安全的方式获取这些BidManager对象的方法,可以使用单例模式,也可以通过其他方式

感谢您的回复-我在阅读评论时也这么认为,但避免返回此类的内部内容-但是,如果另一个对象需要了解当前的投标人,那么如果不返回类的内部内容,又不返回关于单例的内部内容,该如何做-这不被视为反模式吗?另一个类需要什么要确切知道?当时有哪些投标人辛格尔顿是,这就是为什么我建议谨慎,但当你声明一个静态字段时,这是整个程序的一个实例,不管怎样,谢谢你的回复-我在阅读评论时也这么认为,但避免返回此类的内部内容-但是,如果另一个对象需要知道当前的投标人,如果不返回类的内部内容,又不返回单例的内部内容,你会怎么做-这不被视为反模式吗?是什么另一个类需要确切地知道?当时有哪些投标人Singleton是,这就是我建议谨慎的原因,但是当你声明一个静态字段时,这是整个程序的一个实例,所以无论如何你都有。