4

オブジェクトConverterを変換するために JSF 1.2 でカスタムを作成しました。Date日付には非常に特殊な形式があります。SimpleDateFormat以下のコード コメントに示されているフォーマッタ文字列を使用して、コア Java クラスを使用して変換を行うコンバータを実装しました。これはすべてうまくいきます。

私の質問は、スレッドセーフについてです。SimpleDateFormatAPI ドキュメントには、スレッドセーフではないと記載されています。そのため、コンバーター オブジェクトのインスタンスごとに、日付形式オブジェクトの個別のインスタンスを作成しました。ただし、これで十分かどうかはわかりません。私のDateFormatオブジェクトはのメンバーとして保存されますDTGDateConverter

質問: 2 つのスレッドはそれぞれ、JSF の Converter オブジェクトの同じインスタンスに同時にアクセスしますか?

答えが「はい」の場合、私のコンバーターはおそらく危険にさらされています。

/**
 * <p>JSF Converter used to convert from java.util.Date to a string.
 * The SimpleDateFormat format used is: ddHHmm'Z'MMMyy.</p>
 * 
 * <p>Example: October 31st 2010 at 23:59 formats to 312359ZOCT10</p>
 * 
 * @author JTOUGH
 */
public class DTGDateConverter implements Converter {

    private static final Logger logger = 
        LoggerFactory.getLogger(DTGDateConverter.class);

    private static final String EMPTY_STRING = "";

    private static final DateFormat DTG_DATE_FORMAT = 
        MyFormatterUtilities.createDTGInstance();

    // The 'format' family of core Java classes are NOT thread-safe.
    // Each instance of this class needs its own DateFormat object or
    // runs the risk of two request threads accessing it at the same time.
    private final DateFormat df = (DateFormat)DTG_DATE_FORMAT.clone();

    @Override
    public Object getAsObject(
            FacesContext context, 
            UIComponent component, 
            String stringValue)
            throws ConverterException {
        Date date = null;
        // Prevent ParseException when an empty form field is submitted
        // for conversion
        if (stringValue == null || stringValue.equals(EMPTY_STRING)) {
            date = null;
        } else {
            try {
                date = df.parse(stringValue);
            } catch (ParseException e) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Unable to convert string to Date object", e);
                }
                date = null;
            }
        }
        return date;
    }

    @Override
    public String getAsString(
            FacesContext context, 
            UIComponent component, 
            Object objectValue)
            throws ConverterException {
        if (objectValue == null) {
            return null;
        } else if (!(objectValue instanceof Date)) {
            throw new IllegalArgumentException(
                "objectValue is not a Date object");
        } else {
            // Use 'toUpperCase()' to fix mixed case string returned
            // from 'MMM' portion of date format
            return df.format(objectValue).toUpperCase();
        }
    }

}
4

2 に答える 2

7

2 つのスレッドが JSF の Converter オブジェクトの同じインスタンスに同時にアクセスしますか?

コンバーターの使い方次第です。使用する場合

<h:inputWhatever>
    <f:converter converterId="converterId" />
</h:inputWhatever>

次に、ビュー内のすべての入力要素に対して新しいインスタンスが作成されます。これはスレッドセーフです (エンドユーザーが同じセッションの 2 つのブラウザー タブで 2 つの同一のビューを持ち、両方のビューで同時にポストバックを発行するという非常にまれなエッジ ケースを想定してください)。 .

ただし、使用する場合

<h:inputWhatever converter="#{applicationBean.converter}" />

その場合、同じインスタンスがアプリケーション全体のすべてのビューで共有されるため、スレッドセーフではありません。

ただしDataFormat、コンバーターを作成するたびに静的インスタンスを複製しています。その部分はすでにスレッドセーフではありません。インスタンスが別の場所で使用されているため、内部状態が変更されている間にインスタンスのクローンを作成している可能性があります。また、既存のインスタンスのクローンを作成することは、新しいインスタンスを作成するよりも必ずしも安価ではありません。

コンバーターの使用方法に関係なく、スレッドローカル (つまり、メソッド ブロック内) で宣言することをお勧めします。everytimeを作成するコストがDateFormat大きな懸念事項である場合 (プロファイリングしましたか?)、それをJodaTimeに置き換えることを検討してください。

于 2010-12-13T16:30:19.360 に答える
2

日付形式は同期されません。スレッドごとに個別のフォーマット インスタンスを作成することをお勧めします。複数のスレッドが同時にフォーマットにアクセスする場合は、外部で同期する必要があります。

はい、ここではスレッドセーフではありません。

メソッドにローカルに配置し、スレッドごとにインスタンスを作成します

于 2010-12-13T15:51:41.243 に答える