这个类是线程安全的吗?

class Counter {
  private ConcurrentMap<String, AtomicLong> map =
    new ConcurrentHashMap<String, AtomicLong>();
  public long add(String name) {
    if (this.map.get(name) == null) {
      this.map.putIfAbsent(name, new AtomicLong());
    }
    return this.map.get(name).incrementAndGet();
  }
}

你怎么看?

最佳答案

是的,前提是您将 map 制作成最终版。 if 不是必需的,但如果需要,您可以出于性能原因保留它,尽管它很可能不会产生显着的差异:

public long add(String name) {
  this.map.putIfAbsent(name, new AtomicLong());
  return this.map.get(name).incrementAndGet();
}

编辑

为此,我快速测试了两种实现(有和没有检查)。同一字符串上的 1000 万次调用需要:
  • 250 毫秒,检查
  • 480 ms 无检查

  • 这证实了我所说的:除非你调用这个方法数百万次或者它是你代码的性能关键部分,否则它没有区别。

    编辑 2

    完整的测试结果 - 请参阅 BetterCounter ,它会产生更好的结果 。现在该测试非常具体(无争用 + get 始终有效)并且不一定与您的用法相对应。


    public class Test {
    
        public static void main(String args[]) throws IOException {
            Counter count = new Counter();
            LazyCounter lazyCount = new LazyCounter();
            MPCounter mpCount = new MPCounter();
            BetterCounter betterCount = new BetterCounter();
    
            //WARM UP
            for (int i = 0; i < 10_000_000; i++) {
                count.add("abc");
                lazyCount.add("abc");
                mpCount.add("abc");
                betterCount.add("abc");
            }
    
            //TEST
            long start = System.nanoTime();
            for (int i = 0; i < 10_000_000; i++) {
                count.add("abc");
            }
            long end = System.nanoTime();
            System.out.println((end - start) / 1000000);
    
            start = System.nanoTime();
            for (int i = 0; i < 10_000_000; i++) {
                lazyCount.add("abc");
            }
            end = System.nanoTime();
            System.out.println((end - start) / 1000000);
    
            start = System.nanoTime();
            for (int i = 0; i < 10_000_000; i++) {
                mpCount.add("abc");
            }
            end = System.nanoTime();
            System.out.println((end - start) / 1000000);
    
            start = System.nanoTime();
            for (int i = 0; i < 10_000_000; i++) {
                betterCount.add("abc");
            }
            end = System.nanoTime();
            System.out.println((end - start) / 1000000);
        }
    
        static class Counter {
    
            private final ConcurrentMap<String, AtomicLong> map =
                    new ConcurrentHashMap<String, AtomicLong>();
    
            public long add(String name) {
                this.map.putIfAbsent(name, new AtomicLong());
                return this.map.get(name).incrementAndGet();
            }
        }
    
        static class LazyCounter {
    
            private final ConcurrentMap<String, AtomicLong> map =
                    new ConcurrentHashMap<String, AtomicLong>();
    
            public long add(String name) {
                if (this.map.get(name) == null) {
                    this.map.putIfAbsent(name, new AtomicLong());
                }
                return this.map.get(name).incrementAndGet();
            }
        }
    
        static class BetterCounter {
    
            private final ConcurrentMap<String, AtomicLong> map =
                    new ConcurrentHashMap<String, AtomicLong>();
    
                public long add(String name) {
                    AtomicLong counter = this.map.get(name);
                    if (counter != null)
                        return counter.incrementAndGet();
    
                    AtomicLong newCounter = new AtomicLong();
                    counter = this.map.putIfAbsent(name, newCounter);
    
                    return (counter == null ? newCounter.incrementAndGet() : counter.incrementAndGet());
                }
        }
    
        static class MPCounter {
    
            private final ConcurrentMap<String, AtomicLong> map =
                    new ConcurrentHashMap<String, AtomicLong>();
    
            public long add(String name) {
                final AtomicLong newVal = new AtomicLong(),
                        prevVal = map.putIfAbsent(name, newVal);
                return (prevVal != null ? prevVal : newVal).incrementAndGet();
            }
        }
    }
    

    关于java - 它是线程安全机制吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10498303/

    10-12 05:00