Exemple de code simple pour le compteur Java thread-safe
Cet article présente principalement des exemples de code d'implémentation simple de compteurs Java thread-safe, qui ont une certaine valeur de référence. Les amis qui en ont besoin peuvent en apprendre davantage.
Il y a quelques jours, un morceau de code métier nécessitait qu'une variable s'incrémente de 1 chaque jour. Pour cela, j'ai simplement encapsulé un compteur thread-safe, qui permet à une variable de s'incrémenter de 1 chaque jour. Bien entendu, si le projet est redémarré en cours d'exploitation, même si la date est toujours le même jour, le décompte repartira toujours à 1. Par conséquent, il est plus fiable de stocker la valeur du compteur dans la base de données, mais cela n'affecte pas la valeur de ce code. Il est publié maintenant pour référence de ceux qui en ont besoin.
package com.hikvision.cms.rvs.common.util; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; /** * Created by lihong10 on 2017/8/9. * 一个循环计数器,每天从1开始计数,隔天重置为1。 * 可以创建一个该类的全局对象,然后每次使用时候调用其get方法即可,可以保证线程安全性 */ public class CircularCounter { private static final AtomicReferenceFieldUpdater<CircularCounter, AtomicInteger> valueUpdater = AtomicReferenceFieldUpdater.newUpdater(CircularCounter.class, AtomicInteger.class, "value"); //保证内存可见性 private volatile String key; //保证内存可见性 private volatile AtomicInteger value; private static final String DATE_PATTERN = "yyyy-MM-dd"; public CircularCounter() { /** * 这里将key设置为getCurrentDateString() + "sssssssssss" 是为了测试addAndGet()方法中日期发生变化的情况 * 正常使用应该将key初始化为getCurrentDateString() */ this.key = getCurrentDateString() + "sssssssssss"; this.value = new AtomicInteger(0); } /** * 获取计数器加1以后的值 * * @return */ public Integer addAndGet() { AtomicInteger oldValue = value; AtomicInteger newInteger = new AtomicInteger(0); int newVal = -1; String newDateStr = getCurrentDateString(); //日期一致,计数器加1后返回 if (isDateEquals(newDateStr)) { newVal = add(1); return newVal; } //日期不一致,保证有一个线程重置技术器 reSet(oldValue, newInteger, newDateStr); this.key = newDateStr; //重置后加1返回 newVal = add(1); return newVal; } /** * 获取计数器的当前值 * @return */ public Integer get() { return value.get(); } /** * 判断当前日期与老的日期(也即key成员变量记录的值)是否一致 * * @return */ private boolean isDateEquals(String newDateStr) { String oldDateStr = key; if (!isBlank(oldDateStr) && oldDateStr.equals(newDateStr)) { return true; } return false; } /** * 如果日期发生变化,重置计数器,也即将key设置为当前日期,并将value重置为0,重置后才能接着累加, */ private void reSet(AtomicInteger oldValue, AtomicInteger newValue, String newDateStr) { if(valueUpdater.compareAndSet(this, oldValue, newValue)) { System.out.println("线程" + Thread.currentThread().getName() + "发现日期发生变化"); } } /** * 获取当前日期字符串 * * @return */ private String getCurrentDateString() { Date date = new Date(); String newDateStr = new SimpleDateFormat(DATE_PATTERN).format(date); return newDateStr; } /** * 计数器的值加1。采用CAS保证线程安全性 * * @param increment */ private int add(int increment) { return value.addAndGet(increment); } public static boolean isBlank(CharSequence cs) { int strLen; if(cs != null && (strLen = cs.length()) != 0) { for(int i = 0; i < strLen; ++i) { if(!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } else { return true; } } public static void test() { CircularCounter c = new CircularCounter(); AtomicInteger count = new AtomicInteger(0); List<Thread> li = new ArrayList<Thread>(); int size = 10; CountDownLatch latch1 = new CountDownLatch(1); CountDownLatch latch2 = new CountDownLatch(size); for (int i = 0; i < size; i++) { Thread t = new Thread(new CounterRunner(c, latch1, latch2, count), "thread-" + i); li.add(t); t.start(); } System.out.println("start"); latch1.countDown(); try { latch2.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count.get()); System.out.println(c.get()); if(count.get() == c.get()) { System.out.println("该计数器是线程安全的!!!"); } } public static void main(String... args) { for(int i = 0; i < 15; i++) { test(); } } } /** * 测试使用的Runnable对象 */ class CounterRunner implements Runnable { private CircularCounter counter; private CountDownLatch latch1; private CountDownLatch latch2; private AtomicInteger count; public CounterRunner(CircularCounter counter, CountDownLatch latch1, CountDownLatch latch2, AtomicInteger count) { this.latch1 = latch1; this.latch2 = latch2; this.counter = counter; this.count = count; } @Override public void run() { try { latch1.await(); System.out.println("****************"); for (int i = 0; i < 20; i++) { counter.addAndGet(); count.addAndGet(1); } latch2.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } }
Résumé
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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Guide de la racine carrée en Java. Nous discutons ici du fonctionnement de Square Root en Java avec un exemple et son implémentation de code respectivement.

Guide du nombre parfait en Java. Nous discutons ici de la définition, comment vérifier le nombre parfait en Java ?, des exemples d'implémentation de code.

Guide du générateur de nombres aléatoires en Java. Nous discutons ici des fonctions en Java avec des exemples et de deux générateurs différents avec d'autres exemples.

Guide de Weka en Java. Nous discutons ici de l'introduction, de la façon d'utiliser Weka Java, du type de plate-forme et des avantages avec des exemples.

Guide du numéro Armstrong en Java. Nous discutons ici d'une introduction au numéro d'Armstrong en Java ainsi que d'une partie du code.

Guide du nombre de Smith en Java. Nous discutons ici de la définition, comment vérifier le numéro Smith en Java ? exemple avec implémentation de code.

Dans cet article, nous avons conservé les questions d'entretien Java Spring les plus posées avec leurs réponses détaillées. Pour que vous puissiez réussir l'interview.

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est
