2016-03-20 41 views
0

Unikey anahtar tarafından tanımlanan değiştirilebilen nesneler içeren son statik eşzamanlı hashiye sahip bir Singleton Factory var, bu nesneyi "ağır" işlemi başlatarak (xml statik verileri okuduğu için) bu yüzden Bu fabrikada anahtar değer çifti haritası. Şimdiye kadar, haritanın bu başlatmasını ve (bu nesne) Fabrika yüklendikten sonra önbelleğe alabildiğim kadar iyi, ama şimdi sorun şu ki, bu nesne değişebilir olduğundan, her bir iplik, durumunu değiştirebilir ve böylece iş parçacığı her zaman bu nesnenin durumunu alır. Önceki konu.Tekil güvenlik içinde zaten güvenlik

public class TransportDataWriter { 

    public void write(Serializable messageKey, OutputStream outputStream) throws IOException { 
     Message inter = dao.findByMessageKey(messageKey); 
     String mti = messageTypeResolver.determineMTI(messageKey); 
     if (mti != null) { 
     context = populateWriterFormatContext(inter); 
     WriterFormat format = SingletonWriterFactory.getInstance().createWriterFormat(mti); 
     context.setWriterFormatConfiguration(format.getWriterFormatConfiguration()); 
     format.format(context); 
     byte[] databytes = creator.createMessage(context, format); 
     outputStream.write(databytes); 
     } else { 
     throw CORE.getException(1601, messageKey); 
     } 
    } 
} 

Ben sorun WriterFormat örneği her yeni şimdi denir biçimi yöntemiyle sırasında hesaplanan alan değerleri içerdiğini geçerli:

public final class SingletonWriterFactory { 

    private static Map<String, WriterFormat> FORMATTER_MAP = loadMap(); 

    private static class Loader { 
     static final SingletonWriterFactory INSTANCE = new SingletonWriterFactory(); 
    } 

    /** 
    * Returns the single instance of this factory. 
    * 
    * @return The single instance of this factory 
    */ 
    public static SingletonWriterFactory getInstance() { 
     return Loader.INSTANCE; 
    } 

    private static Map<String, WriterFormat> loadMap() { 
    Map<String, WriterFormat> formatterMap = new ConcurrentHashMap<String,WriterFormat>(); 
    Configuration config = ConfigurationFactory.getInstance().getConfiguration(CONFIG_FILE); 
    List<WriterFormatConfiguration> cfgs = getInstance().getWriterFormatConfigurations(config); 
    WriterFormat [] formatters = getInstance().createWriterFormats(config, cfgs); 
    for (int i = 0; i < formatters.length; i++) { 
     String formatterId = formatters[i].getId(); 
     if (!StringUtils.isBlank(formatterId)) { 
      formatterMap.put(formatterId, formatters[i]); 
     } 
    } 
    return formatterMap; 
    } 


    public synchronized WriterFormat createWriterFormat(String id) { 
    if (FORMATTER_MAP != null && !FORMATTER_MAP.containsKey(id)) { 
     Configuration config = ConfigurationFactory.getInstance().getConfiguration(CONFIG_FILE); 
     List<WriterFormatConfiguration> cfgs = getWriterFormatConfigurations(config); 
     WriterFormat[] formatters = createWriterFormats(config, cfgs); 
     for (int i = 0; i < formatters.length; i++) { 
      if (formatters[i].getWriterFormatConfiguration().getId().equals(id)) { 
       FORMATTER_MAP.put(id, formatters[i]); 
       return formatters[i]; 
      } 
     } 
    } 
    return FORMATTER_MAP.get(id); 
    } 
} 

Şimdi, aşağıdaki gibi hep birlikte bu kravat bir sınıf var WriterFormat tarafından kapsüllenmiş önceki thread değerlerinden geri dönen değerler yazılır, tablonun üzerine yazılır, ancak önceki iş parçacığı bundan daha fazla alana sahip olduğunda, bu alan değerinin de "kendi" mesajını vermesi yazdırılır.

Düzenleme: alanları altında yatan WriterFormat klonlanmış
1. Kullanma apache SerializationUtils: Şimdi aşağıdaki yaptık
. Bu, tüm iş parçacığının WriterFormat tarafından kapsüllenmiş alanların kopyalarını alacağından emin olur.
2. Hem senkronize edilmiş hem de get/setter ile birlikte MessageFields'ın senkronize listesini bulunduran OutgoingMessage adlı yeni veri türü oluşturdum.

Şimdi benim kod aşağıda benziyor:

public void write(Serializable messageKey, OutputStream outputStream) throws IOException { 
    Message inter = dao.findByMessageKey(messageKey); 
    String mti = messageTypeResolver.determineMTI(messageKey); 
    if (mti != null) { 
    context = populateWriterFormatContext(inter); 
    WriterFormat format = SingletonWriterFactory.getInstance().createWriterFormat(mti); 
    context.setWriterFormatConfiguration(format.getWriterFormatConfiguration()); 
    OutgoingMessage m = new OutgoingMessage();   
    format.format(context,m); 
    byte[] databytes = creator.createMessage(context, m); 
    outputStream.write(databytes); 
    } else { 
    throw CORE.getException(1601, messageKey); 
    } 
} 

OutgoingMessage aşağıda klonlanmış alanların sadece sahibidir:

public final class OutgoingMessage implements Serializable { 

/** 
* Thread safe collection of OutgoingMessageField field. 
*/ 
private Collection<OutgoingMessageField> messageField = 
     Collections.synchronizedList(new ArrayList<OutgoingMessageField>()); 

/** 
* 
* @param field 
*/ 
public synchronized void setOutgoingMessageField(OutgoingMessageField field) { 
    messageField.add(field); 
} 

/** 
* 
* @return 
*/ 
public synchronized Collection<OutgoingMessageField> getOutgoingMessageFields() { 
    return messageField; 
} 
} 

Yani kadar hiçbir yarış durumu veya çok diş sorunu. Ama gözden geçirilmek için bu koda ihtiyacım var.

cevap

0

Eğer doğru anlıyorsam, bunları WriterFormat örneklerini "önbelleğe alırsınız", çünkü bunları xml'den okumak pahalıdır ve sadece bir kez yapmak istersiniz. Hangisi mantıklı. Ancak, daha önce oluşturulmuş ve önbelleğe alınmış olandan yeni bir WriterFormat "yapısını kopyalamak" ne kadar pahalı? WriterFormat kendi uygulamanız nedir? ulaşmak istediğiniz ve ne kadar pahalı ne bağlı kopya ya

  • her iş parçacığı için yeni bir kopyasını oluşturma veya
  • senkronize WriterFormat ilgili arayüz yöntemlerini olun olurdu. Daha da iyisi, bunun için senkronize bir sarıcı sağlar.

Kopyalama devasa bir ek yük değilse, bunun için giderdim, böylece iş parçacıkları arasında hiçbir durum paylaşılmaz.

+0

Her bir iş parçacığı için yazıcının yeni kopyasının oluşturulması, bu nesnenin gerçekleştirilmesi amacını aşacaktır. İkinci seçenek bana uygun görünüyor, ayrıca WriterFormat format = SingletonWriterFactory.getInstance(). CreateWriterFormat (mti) yapabilir miyim? Biçim örneğini değişken olarak, sadece düşünüyor musunuz? –

+0

Uçucu, yönteminizin çağrıldığını veya örneğinizde senkronize edilmesini etkilemez. Bir referansta uçucu sadece, referansın (örneğiniz için "adresi" tutan bellek bloğu) kendisinin uçucu olduğu anlamına gelir. Ayrıca, orijinal yayınınızda, bir XML'den okuma yapıp nesneyi ondan oluşturmanın pahalı olduğuna işaret ederek önbelleğe alma konusundaki motivasyonunuzu açıklarsınız. Mevcut örneğinizi kopyalamak pahalı olmayabilir, çünkü tekrar okunup ayrıştırılması gerekmez. Sadece devlet kopyalanmalıdır. – vnagy

+0

Sorununuzun kökü, örneğinizin _state_'inin iş parçacıkları tarafından paylaşıldığı ve eşzamanlı kullanım tarafından karmaşıklaştığı için, her iş parçacığından kopyalar, göründüğü kadar üretken olmayabilir. Örneğinizin durumunu zorla korumaya çalışmak yerine, sorununuzu tamamen farklı nesneler vererek bırakabilirsiniz. Söylediğim gibi, eğer örneğiniz zaten hafızadaysa, kopyalamak o kadar da büyük bir şey değil. Burada ana nokta: _ Eğer durumları konuları arasında paylaşmak için gerçekten iyi bir neden yoksa, o zaman yapmayın. – vnagy