Home | History | Annotate | Download | only in concurrent
      1 // Copyright 2011 Google Inc. All Rights Reserved.
      2 
      3 package com.google.common.util.concurrent;
      4 
      5 import com.google.common.collect.ImmutableMap;
      6 import com.google.common.collect.Sets;
      7 import com.google.common.testing.NullPointerTester;
      8 
      9 import junit.framework.TestCase;
     10 
     11 import java.util.Map;
     12 import java.util.Random;
     13 import java.util.Set;
     14 import java.util.concurrent.ExecutorService;
     15 import java.util.concurrent.Executors;
     16 import java.util.concurrent.TimeUnit;
     17 import java.util.concurrent.atomic.AtomicLong;
     18 
     19 /**
     20  * Tests for {@link AtomicLongMap}.
     21  *
     22  * @author schmoe (at) google.com (mike nonemacher)
     23  */
     24 public class AtomicLongMapTest extends TestCase {
     25   private static final int ITERATIONS = 100;
     26   private static final int MAX_ADDEND = 100;
     27 
     28   private Random random = new Random(301);
     29 
     30   public void testNulls() throws Exception {
     31     NullPointerTester tester = new NullPointerTester();
     32     tester.testAllPublicConstructors(AtomicLongMap.class);
     33     tester.testAllPublicStaticMethods(AtomicLongMap.class);
     34     AtomicLongMap<Object> map = AtomicLongMap.create();
     35     tester.testAllPublicInstanceMethods(map);
     36   }
     37 
     38   public void testCreate_map() {
     39     Map<String, Long> in = ImmutableMap.of("1", 1L, "2", 2L, "3", 3L);
     40     AtomicLongMap<String> map = AtomicLongMap.create(in);
     41     assertFalse(map.isEmpty());
     42     assertSame(3, map.size());
     43     assertTrue(map.containsKey("1"));
     44     assertTrue(map.containsKey("2"));
     45     assertTrue(map.containsKey("3"));
     46     assertEquals(1L, map.get("1"));
     47     assertEquals(2L, map.get("2"));
     48     assertEquals(3L, map.get("3"));
     49   }
     50 
     51   public void testIncrementAndGet() {
     52     AtomicLongMap<String> map = AtomicLongMap.create();
     53     String key = "key";
     54     for (int i = 0; i < ITERATIONS; i++) {
     55       long before = map.get(key);
     56       long result = map.incrementAndGet(key);
     57       long after = map.get(key);
     58       assertEquals(before + 1, after);
     59       assertEquals(after, result);
     60     }
     61     assertEquals(1, map.size());
     62     assertTrue(!map.isEmpty());
     63     assertTrue(map.containsKey(key));
     64     assertEquals(ITERATIONS, (int) map.get(key));
     65   }
     66 
     67   public void testIncrementAndGet_zero() {
     68     AtomicLongMap<String> map = AtomicLongMap.create();
     69     String key = "key";
     70     assertEquals(0L, map.get(key));
     71     assertFalse(map.containsKey(key));
     72 
     73     assertEquals(1L, map.incrementAndGet(key));
     74     assertEquals(1L, map.get(key));
     75 
     76     assertEquals(0L, map.decrementAndGet(key));
     77     assertEquals(0L, map.get(key));
     78     assertTrue(map.containsKey(key));
     79 
     80     assertEquals(1L, map.incrementAndGet(key));
     81     assertEquals(1L, map.get(key));
     82   }
     83 
     84   public void testGetAndIncrement() {
     85     AtomicLongMap<String> map = AtomicLongMap.create();
     86     String key = "key";
     87     for (int i = 0; i < ITERATIONS; i++) {
     88       long before = map.get(key);
     89       long result = map.getAndIncrement(key);
     90       long after = map.get(key);
     91       assertEquals(before + 1, after);
     92       assertEquals(before, result);
     93     }
     94     assertEquals(1, map.size());
     95     assertTrue(!map.isEmpty());
     96     assertTrue(map.containsKey(key));
     97     assertEquals(ITERATIONS, (int) map.get(key));
     98   }
     99 
    100   public void testGetAndIncrement_zero() {
    101     AtomicLongMap<String> map = AtomicLongMap.create();
    102     String key = "key";
    103     assertEquals(0L, map.get(key));
    104     assertFalse(map.containsKey(key));
    105 
    106     assertEquals(0L, map.getAndIncrement(key));
    107     assertEquals(1L, map.get(key));
    108 
    109     assertEquals(1L, map.getAndDecrement(key));
    110     assertEquals(0L, map.get(key));
    111     assertTrue(map.containsKey(key));
    112 
    113     assertEquals(0L, map.getAndIncrement(key));
    114     assertEquals(1L, map.get(key));
    115   }
    116 
    117   public void testDecrementAndGet() {
    118     AtomicLongMap<String> map = AtomicLongMap.create();
    119     String key = "key";
    120     for (int i = 0; i < ITERATIONS; i++) {
    121       long before = map.get(key);
    122       long result = map.decrementAndGet(key);
    123       long after = map.get(key);
    124       assertEquals(before - 1, after);
    125       assertEquals(after, result);
    126     }
    127     assertEquals(1, map.size());
    128     assertTrue(!map.isEmpty());
    129     assertTrue(map.containsKey(key));
    130     assertEquals(-1 * ITERATIONS, (int) map.get(key));
    131   }
    132 
    133   public void testDecrementAndGet_zero() {
    134     AtomicLongMap<String> map = AtomicLongMap.create();
    135     String key = "key";
    136     assertEquals(0L, map.get(key));
    137     assertFalse(map.containsKey(key));
    138 
    139     assertEquals(-1L, map.decrementAndGet(key));
    140     assertEquals(-1L, map.get(key));
    141 
    142     assertEquals(0L, map.incrementAndGet(key));
    143     assertEquals(0L, map.get(key));
    144     assertTrue(map.containsKey(key));
    145 
    146     assertEquals(-1L, map.decrementAndGet(key));
    147     assertEquals(-1L, map.get(key));
    148   }
    149 
    150   public void testGetAndDecrement() {
    151     AtomicLongMap<String> map = AtomicLongMap.create();
    152     String key = "key";
    153     for (int i = 0; i < ITERATIONS; i++) {
    154       long before = map.get(key);
    155       long result = map.getAndDecrement(key);
    156       long after = map.get(key);
    157       assertEquals(before - 1, after);
    158       assertEquals(before, result);
    159     }
    160     assertEquals(1, map.size());
    161     assertTrue(!map.isEmpty());
    162     assertTrue(map.containsKey(key));
    163     assertEquals(-1 * ITERATIONS, (int) map.get(key));
    164   }
    165 
    166   public void testGetAndDecrement_zero() {
    167     AtomicLongMap<String> map = AtomicLongMap.create();
    168     String key = "key";
    169     assertEquals(0L, map.get(key));
    170     assertFalse(map.containsKey(key));
    171 
    172     assertEquals(0L, map.getAndDecrement(key));
    173     assertEquals(-1L, map.get(key));
    174 
    175     assertEquals(-1L, map.getAndIncrement(key));
    176     assertEquals(0L, map.get(key));
    177     assertTrue(map.containsKey(key));
    178 
    179     assertEquals(0L, map.getAndDecrement(key));
    180     assertEquals(-1L, map.get(key));
    181   }
    182 
    183   public void testAddAndGet() {
    184     AtomicLongMap<String> map = AtomicLongMap.create();
    185     String key = "key";
    186     long addend = random.nextInt(MAX_ADDEND);
    187     for (int i = 0; i < ITERATIONS; i++) {
    188       long before = map.get(key);
    189       long result = map.addAndGet(key, addend);
    190       long after = map.get(key);
    191       assertEquals(before + addend, after);
    192       assertEquals(after, result);
    193       addend = after;
    194     }
    195     assertEquals(1, map.size());
    196     assertTrue(!map.isEmpty());
    197     assertTrue(map.containsKey(key));
    198   }
    199 
    200   public void testAddAndGet_zero() {
    201     AtomicLongMap<String> map = AtomicLongMap.create();
    202     String key = "key";
    203     long value = random.nextInt(MAX_ADDEND);
    204     assertEquals(0L, map.get(key));
    205     assertFalse(map.containsKey(key));
    206 
    207     assertEquals(value, map.addAndGet(key, value));
    208     assertEquals(value, map.get(key));
    209 
    210     assertEquals(0L, map.addAndGet(key, -1 * value));
    211     assertEquals(0L, map.get(key));
    212     assertTrue(map.containsKey(key));
    213 
    214     assertEquals(value, map.addAndGet(key, value));
    215     assertEquals(value, map.get(key));
    216   }
    217 
    218   public void testGetAndAdd() {
    219     AtomicLongMap<String> map = AtomicLongMap.create();
    220     String key = "key";
    221     long addend = random.nextInt(MAX_ADDEND);
    222     for (int i = 0; i < ITERATIONS; i++) {
    223       long before = map.get(key);
    224       long result = map.getAndAdd(key, addend);
    225       long after = map.get(key);
    226       assertEquals(before + addend, after);
    227       assertEquals(before, result);
    228       addend = after;
    229     }
    230     assertEquals(1, map.size());
    231     assertTrue(!map.isEmpty());
    232     assertTrue(map.containsKey(key));
    233   }
    234 
    235   public void testGetAndAdd_zero() {
    236     AtomicLongMap<String> map = AtomicLongMap.create();
    237     String key = "key";
    238     long value = random.nextInt(MAX_ADDEND);
    239     assertEquals(0L, map.get(key));
    240     assertFalse(map.containsKey(key));
    241 
    242     assertEquals(0L, map.getAndAdd(key, value));
    243     assertEquals(value, map.get(key));
    244 
    245     assertEquals(value, map.getAndAdd(key, -1 * value));
    246     assertEquals(0L, map.get(key));
    247     assertTrue(map.containsKey(key));
    248 
    249     assertEquals(0L, map.getAndAdd(key, value));
    250     assertEquals(value, map.get(key));
    251   }
    252 
    253   public void testPut() {
    254     AtomicLongMap<String> map = AtomicLongMap.create();
    255     String key = "key";
    256     long newValue = random.nextInt(MAX_ADDEND);
    257     for (int i = 0; i < ITERATIONS; i++) {
    258       long before = map.get(key);
    259       long result = map.put(key, newValue);
    260       long after = map.get(key);
    261       assertEquals(newValue, after);
    262       assertEquals(before, result);
    263       newValue += newValue;
    264     }
    265     assertEquals(1, map.size());
    266     assertTrue(!map.isEmpty());
    267     assertTrue(map.containsKey(key));
    268   }
    269 
    270   public void testPut_zero() {
    271     AtomicLongMap<String> map = AtomicLongMap.create();
    272     String key = "key";
    273     long value = random.nextInt(MAX_ADDEND);
    274     assertEquals(0L, map.get(key));
    275     assertFalse(map.containsKey(key));
    276 
    277     assertEquals(0L, map.put(key, value));
    278     assertEquals(value, map.get(key));
    279 
    280     assertEquals(value, map.put(key, 0L));
    281     assertEquals(0L, map.get(key));
    282     assertTrue(map.containsKey(key));
    283 
    284     assertEquals(0L, map.put(key, value));
    285     assertEquals(value, map.get(key));
    286   }
    287 
    288   public void testPutAll() {
    289     Map<String, Long> in = ImmutableMap.of("1", 1L, "2", 2L, "3", 3L);
    290     AtomicLongMap<String> map = AtomicLongMap.create();
    291     assertTrue(map.isEmpty());
    292     assertSame(0, map.size());
    293     assertFalse(map.containsKey("1"));
    294     assertFalse(map.containsKey("2"));
    295     assertFalse(map.containsKey("3"));
    296     assertEquals(0L, map.get("1"));
    297     assertEquals(0L, map.get("2"));
    298     assertEquals(0L, map.get("3"));
    299 
    300     map.putAll(in);
    301     assertFalse(map.isEmpty());
    302     assertSame(3, map.size());
    303     assertTrue(map.containsKey("1"));
    304     assertTrue(map.containsKey("2"));
    305     assertTrue(map.containsKey("3"));
    306     assertEquals(1L, map.get("1"));
    307     assertEquals(2L, map.get("2"));
    308     assertEquals(3L, map.get("3"));
    309   }
    310 
    311   public void testPutIfAbsent() {
    312     AtomicLongMap<String> map = AtomicLongMap.create();
    313     String key = "key";
    314     long newValue = random.nextInt(MAX_ADDEND);
    315     for (int i = 0; i < ITERATIONS; i++) {
    316       long before = map.get(key);
    317       long result = map.putIfAbsent(key, newValue);
    318       long after = map.get(key);
    319       assertEquals(before, result);
    320       assertEquals(before == 0 ? newValue : before, after);
    321 
    322       map.remove(key);
    323       before = map.get(key);
    324       result = map.putIfAbsent(key, newValue);
    325       after = map.get(key);
    326       assertEquals(0, before);
    327       assertEquals(before, result);
    328       assertEquals(newValue, after);
    329 
    330       map.put(key, 0L);
    331       before = map.get(key);
    332       result = map.putIfAbsent(key, newValue);
    333       after = map.get(key);
    334       assertEquals(0, before);
    335       assertEquals(before, result);
    336       assertEquals(newValue, after);
    337 
    338       newValue += newValue;
    339     }
    340     assertEquals(1, map.size());
    341     assertTrue(!map.isEmpty());
    342     assertTrue(map.containsKey(key));
    343   }
    344 
    345   public void testPutIfAbsent_zero() {
    346     AtomicLongMap<String> map = AtomicLongMap.create();
    347     String key = "key";
    348     long value = random.nextInt(MAX_ADDEND);
    349     assertEquals(0L, map.get(key));
    350     assertFalse(map.containsKey(key));
    351 
    352     assertEquals(0L, map.putIfAbsent(key, value));
    353     assertEquals(value, map.get(key));
    354 
    355     assertEquals(value, map.put(key, 0L));
    356     assertEquals(0L, map.get(key));
    357     assertTrue(map.containsKey(key));
    358 
    359     assertEquals(0L, map.putIfAbsent(key, value));
    360     assertEquals(value, map.get(key));
    361   }
    362 
    363   public void testReplace() {
    364     AtomicLongMap<String> map = AtomicLongMap.create();
    365     String key = "key";
    366     long newValue = random.nextInt(MAX_ADDEND);
    367     for (int i = 0; i < ITERATIONS; i++) {
    368       long before = map.get(key);
    369       assertFalse(map.replace(key, before + 1, newValue + 1));
    370       assertFalse(map.replace(key, before - 1, newValue - 1));
    371       assertTrue(map.replace(key, before, newValue));
    372       long after = map.get(key);
    373       assertEquals(newValue, after);
    374       newValue += newValue;
    375     }
    376     assertEquals(1, map.size());
    377     assertTrue(!map.isEmpty());
    378     assertTrue(map.containsKey(key));
    379   }
    380 
    381   public void testReplace_zero() {
    382     AtomicLongMap<String> map = AtomicLongMap.create();
    383     String key = "key";
    384     long value = random.nextInt(MAX_ADDEND);
    385     assertEquals(0L, map.get(key));
    386     assertFalse(map.containsKey(key));
    387 
    388     assertTrue(map.replace(key, 0L, value));
    389     assertEquals(value, map.get(key));
    390 
    391     assertTrue(map.replace(key, value, 0L));
    392     assertEquals(0L, map.get(key));
    393     assertTrue(map.containsKey(key));
    394 
    395     assertTrue(map.replace(key, 0L, value));
    396     assertEquals(value, map.get(key));
    397   }
    398 
    399   public void testRemove() {
    400     AtomicLongMap<String> map = AtomicLongMap.create();
    401     String key = "key";
    402     assertEquals(0, map.size());
    403     assertTrue(map.isEmpty());
    404     assertEquals(0L, map.remove(key));
    405 
    406     long newValue = random.nextInt(MAX_ADDEND);
    407     for (int i = 0; i < ITERATIONS; i++) {
    408       map.put(key, newValue);
    409       assertTrue(map.containsKey(key));
    410 
    411       long before = map.get(key);
    412       long result = map.remove(key);
    413       long after = map.get(key);
    414       assertFalse(map.containsKey(key));
    415       assertEquals(before, result);
    416       assertEquals(0L, after);
    417       newValue += newValue;
    418     }
    419     assertEquals(0, map.size());
    420     assertTrue(map.isEmpty());
    421   }
    422 
    423   public void testRemove_zero() {
    424     AtomicLongMap<String> map = AtomicLongMap.create();
    425     String key = "key";
    426     assertEquals(0L, map.get(key));
    427     assertFalse(map.containsKey(key));
    428 
    429     assertEquals(0L, map.remove(key));
    430     assertEquals(0L, map.get(key));
    431     assertFalse(map.containsKey(key));
    432 
    433     assertEquals(0L, map.put(key, 0L));
    434     assertEquals(0L, map.get(key));
    435     assertTrue(map.containsKey(key));
    436 
    437     assertEquals(0L, map.remove(key));
    438     assertEquals(0L, map.get(key));
    439     assertFalse(map.containsKey(key));
    440   }
    441 
    442   public void testRemoveValue() {
    443     AtomicLongMap<String> map = AtomicLongMap.create();
    444     String key = "key";
    445     assertEquals(0, map.size());
    446     assertTrue(map.isEmpty());
    447     assertFalse(map.remove(key, 0L));
    448 
    449     long newValue = random.nextInt(MAX_ADDEND);
    450     for (int i = 0; i < ITERATIONS; i++) {
    451       map.put(key, newValue);
    452       assertTrue(map.containsKey(key));
    453 
    454       long before = map.get(key);
    455       assertFalse(map.remove(key, newValue + 1));
    456       assertFalse(map.remove(key, newValue - 1));
    457       assertTrue(map.remove(key, newValue));
    458       long after = map.get(key);
    459       assertFalse(map.containsKey(key));
    460       assertEquals(0L, after);
    461       newValue += newValue;
    462     }
    463     assertEquals(0, map.size());
    464     assertTrue(map.isEmpty());
    465   }
    466 
    467   public void testRemoveValue_zero() {
    468     AtomicLongMap<String> map = AtomicLongMap.create();
    469     String key = "key";
    470     assertEquals(0L, map.get(key));
    471     assertFalse(map.containsKey(key));
    472 
    473     assertFalse(map.remove(key, 0L));
    474     assertEquals(0L, map.get(key));
    475     assertFalse(map.containsKey(key));
    476 
    477     assertEquals(0L, map.put(key, 0L));
    478     assertEquals(0L, map.get(key));
    479     assertTrue(map.containsKey(key));
    480 
    481     assertTrue(map.remove(key, 0L));
    482     assertEquals(0L, map.get(key));
    483     assertFalse(map.containsKey(key));
    484   }
    485 
    486   public void testRemoveZeros() {
    487     AtomicLongMap<Object> map = AtomicLongMap.create();
    488     Set<Object> nonZeroKeys = Sets.newHashSet();
    489     for (int i = 0; i < ITERATIONS; i++) {
    490       Object key = new Object();
    491       long value = i % 2;
    492       map.put(key, value);
    493       if (value != 0L) {
    494         nonZeroKeys.add(key);
    495       }
    496     }
    497     assertEquals(ITERATIONS, map.size());
    498     assertTrue(map.asMap().containsValue(0L));
    499 
    500     map.removeAllZeros();
    501     assertFalse(map.asMap().containsValue(0L));
    502     assertEquals(ITERATIONS / 2, map.size());
    503     assertEquals(nonZeroKeys, map.asMap().keySet());
    504   }
    505 
    506   public void testClear() {
    507     AtomicLongMap<Object> map = AtomicLongMap.create();
    508     for (int i = 0; i < ITERATIONS; i++) {
    509       map.put(new Object(), i);
    510     }
    511     assertEquals(ITERATIONS, map.size());
    512 
    513     map.clear();
    514     assertEquals(0, map.size());
    515     assertTrue(map.isEmpty());
    516   }
    517 
    518   public void testSum() {
    519     AtomicLongMap<Object> map = AtomicLongMap.create();
    520     long sum = 0;
    521     for (int i = 0; i < ITERATIONS; i++) {
    522       map.put(new Object(), i);
    523       sum += i;
    524     }
    525     assertEquals(ITERATIONS, map.size());
    526     assertEquals(sum, map.sum());
    527   }
    528 
    529   public void testEmpty() {
    530     AtomicLongMap<String> map = AtomicLongMap.create();
    531     assertEquals(0L, map.get("a"));
    532     assertEquals(0, map.size());
    533     assertTrue(map.isEmpty());
    534     assertFalse(map.remove("a", 1L));
    535     assertFalse(map.remove("a", 0L));
    536     assertFalse(map.replace("a", 1L, 0L));
    537   }
    538 
    539   public void testModify_basher() throws InterruptedException {
    540     int nTasks = 3000;
    541     int nThreads = 100;
    542     final int getsPerTask = 1000;
    543     final int deltaRange = 10000;
    544     final String key = "key";
    545 
    546     final AtomicLong sum = new AtomicLong();
    547     final AtomicLongMap<String> map = AtomicLongMap.create();
    548 
    549     ExecutorService threadPool = Executors.newFixedThreadPool(nThreads);
    550     for (int i = 0; i < nTasks; i++) {
    551       threadPool.submit(new Runnable() {
    552         @Override public void run() {
    553           int threadSum = 0;
    554           for (int j = 0; j < getsPerTask; j++) {
    555             long delta = random.nextInt(deltaRange);
    556             int behavior = random.nextInt(10);
    557             switch (behavior) {
    558               case 0:
    559                 map.incrementAndGet(key);
    560                 threadSum++;
    561                 break;
    562               case 1:
    563                 map.decrementAndGet(key);
    564                 threadSum--;
    565                 break;
    566               case 2:
    567                 map.addAndGet(key, delta);
    568                 threadSum += delta;
    569                 break;
    570               case 3:
    571                 map.getAndIncrement(key);
    572                 threadSum++;
    573                 break;
    574               case 4:
    575                 map.getAndDecrement(key);
    576                 threadSum--;
    577                 break;
    578               case 5:
    579                 map.getAndAdd(key, delta);
    580                 threadSum += delta;
    581                 break;
    582               case 6:
    583                 long oldValue = map.put(key, delta);
    584                 threadSum += delta - oldValue;
    585                 break;
    586               case 7:
    587                 oldValue = map.get(key);
    588                 if (map.replace(key, oldValue, delta)) {
    589                   threadSum += delta - oldValue;
    590                 }
    591                 break;
    592               case 8:
    593                 oldValue = map.remove(key);
    594                 threadSum -= oldValue;
    595                 break;
    596               case 9:
    597                 oldValue = map.get(key);
    598                 if (map.remove(key, oldValue)) {
    599                   threadSum -= oldValue;
    600                 }
    601                 break;
    602               default:
    603                 throw new AssertionError();
    604             }
    605           }
    606           sum.addAndGet(threadSum);
    607         }
    608       });
    609     }
    610 
    611     threadPool.shutdown();
    612     assertTrue(threadPool.awaitTermination(300, TimeUnit.SECONDS));
    613 
    614     assertEquals(sum.get(), map.get(key));
    615   }
    616 }
    617