Maison > Java > JavaBase > le corps du texte

Pourquoi le fil de discussion simpledateformat est-il dangereux ?

青灯夜游
Libérer: 2023-01-13 00:39:56
original
17242 Les gens l'ont consulté

Cause : dans un environnement multithread, lorsque plusieurs threads utilisent le même objet SimpleDateFormat (comme une modification statique) en même temps, par exemple en appelant la méthode format, plusieurs threads appelleront la méthode calender.setTime en même temps, ce qui entraîne une modification du temps par d'autres threads, de sorte que le thread n'est pas sécurisé.

Pourquoi le fil de discussion simpledateformat est-il dangereux ?

L'environnement d'exploitation de ce tutoriel : système Windows 7, version Java 8, ordinateur DELL G3.

Vérification du fil de discussion non sécurisé :

/**
 * SimpleDateFormat线程安全测试
 * 〈功能详细描述〉
 *
 * @author 17090889
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class SimpleDateFormatTest {
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest"));

    public void test() {
        while (true) {
            poolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    String dateString = simpleDateFormat.format(new Date());
                    try {
                        Date parseDate = simpleDateFormat.parse(dateString);
                        String dateString2 = simpleDateFormat.format(parseDate);
                        System.out.println(dateString.equals(dateString2));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
Copier après la connexion

Sortie :

  true
  false
  true
  true
  false
Copier après la connexion

false apparaît, indiquant que le fil de discussion n'est pas sécurisé

1. Comme vous pouvez le voir grâce à la méthode

public StringBuffer format(Date date, StringBuffer toAppendTo,
                               FieldPosition pos)
    {
        pos.beginIndex = pos.endIndex = 0;
        return format(date, toAppendTo, pos.getFieldDelegate());
    }

    // Called from Format after creating a FieldDelegate
    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
        calendar.setTime(date);

        boolean useDateFormatSymbols = useDateFormatSymbols();

        for (int i = 0; i < compiledPattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            }

            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;

            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;

            default:
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }
Copier après la connexion
 protected Calendar calendar;
Copier après la connexion

, le calendrier variable est partagé entre plusieurs threads et le calendrier est modifié. Par conséquent, dans un environnement multithread, lorsque plusieurs threads utilisent le même objet SimpleDateFormat (comme une modification statique) en même temps, par exemple en appelant la méthode format, plusieurs threads appelleront la méthode calender.setTime en même temps, provoquant le temps d'être modifié par d'autres threads. Par conséquent, les threads ne sont pas sûrs.

De plus, la méthode parse est également thread-unsafe. La méthode parse appelle en fait l'établissement de CalenderBuilder pour l'analyse. Les principales étapes de la méthode ne sont pas des opérations atomiques.

Solution :

1. Définir SimpleDateFormat comme variable locale

2. Ajouter un verrou de synchronisation de thread : synchronisé(lock)

 3. En utilisant ThreadLocal, chaque thread possède sa propre copie de l'objet SimpleDateFormat. Tels que :

/**
 * SimpleDateFormat线程安全测试
 * 〈功能详细描述〉
 *
 * @author 17090889
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class SimpleDateFormatTest {
        private static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() {
        @Override
        protected SimpleDateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };
    //    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest"));

    public void test() {
        while (true) {
            poolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    SimpleDateFormat simpleDateFormat = THREAD_LOCAL.get();
                    if (simpleDateFormat == null) {
                        simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    String dateString = simpleDateFormat.format(new Date());
                    try {
                        Date parseDate = simpleDateFormat.parse(dateString);
                        String dateString2 = simpleDateFormat.format(parseDate);
                        System.out.println(dateString.equals(dateString2));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    } finally {
                        local.remove();
                    }
                }
            });
        }
    }
}
Copier après la connexion

4. Utilisez DateTimeFormatter au lieu de SimpleDateFormat

DateTimeFormatter est thread-safe et fournit de nombreuses méthodes de formatage par défaut. Des méthodes de formatage personnalisées peuvent également être créées via la méthode ofPattern.

(1) Exemple de format de date :

 LocalDateTime localDateTime = LocalDateTime.now();
 System.out.println(localDateTime); // 2019-11-20T15:04:29.017
 DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
 String strDate=localDateTime.format(dtf);
 System.out.println(strDate); // 2019/23/20 15:23:46
Copier après la connexion

(2) Analyser la date

 DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
 LocalDateTime localDateTime=LocalDateTime.parse("2019/11/20 15:23:46",dtf);
 System.out.println(localDateTime); // 2019-11-20T15:23:46
Copier après la connexion

Tutoriels vidéo associés recommandés : Tutoriel vidéo Java

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal