1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.
   7  *
   8  * This code is distributed in the hope that it will be useful, but WITHOUT
   9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  11  * version 2 for more details (a copy is included in the LICENSE file that
  12  * accompanied this code).
  13  *
  14  * You should have received a copy of the GNU General Public License version
  15  * 2 along with this work; if not, write to the Free Software Foundation,
  16  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  17  *
  18  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  19  * or visit www.oracle.com if you need additional information or have any
  20  * questions.
  21  */
  22 
  23 /*
  24  * This file is available under and governed by the GNU General Public
  25  * License version 2 only, as published by the Free Software Foundation.
  26  * However, the following notice accompanied the original version of this
  27  * file:
  28  *
  29  * Written by Doug Lea with assistance from members of JCP JSR-166
  30  * Expert Group and released to the public domain, as explained at
  31  * http://creativecommons.org/publicdomain/zero/1.0/
  32  * Other contributors include Andrew Wright, Jeffrey Hayes,
  33  * Pat Fisher, Mike Judd.
  34  */
  35 
  36 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
  37 
  38 import junit.framework.Test;
  39 import junit.framework.TestSuite;
  40 
  41 public class AtomicReferenceFieldUpdaterTest extends JSR166TestCase {
  42     volatile Integer x = null;
  43     protected volatile Integer protectedField;
  44     private volatile Integer privateField;
  45     Object z;
  46     Integer w;
  47     volatile int i;
  48 
  49     public static void main(String[] args) {
  50         main(suite(), args);
  51     }
  52     public static Test suite() {
  53         return new TestSuite(AtomicReferenceFieldUpdaterTest.class);
  54     }
  55 
  56     // for testing subclass access
  57     static class AtomicReferenceFieldUpdaterTestSubclass extends AtomicReferenceFieldUpdaterTest {
  58         public void checkPrivateAccess() {
  59             try {
  60                 AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
  61                     AtomicReferenceFieldUpdater.newUpdater
  62                     (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
  63                 shouldThrow();
  64             } catch (RuntimeException success) {
  65                 assertNotNull(success.getCause());
  66             }
  67         }
  68 
  69         public void checkCompareAndSetProtectedSub() {
  70             AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
  71                 AtomicReferenceFieldUpdater.newUpdater
  72                 (AtomicReferenceFieldUpdaterTest.class, Integer.class, "protectedField");
  73             this.protectedField = one;
  74             assertTrue(a.compareAndSet(this, one, two));
  75             assertTrue(a.compareAndSet(this, two, m4));
  76             assertSame(m4, a.get(this));
  77             assertFalse(a.compareAndSet(this, m5, seven));
  78             assertNotSame(seven, a.get(this));
  79             assertTrue(a.compareAndSet(this, m4, seven));
  80             assertSame(seven, a.get(this));
  81         }
  82     }
  83 
  84     static class UnrelatedClass {
  85         public void checkPackageAccess(AtomicReferenceFieldUpdaterTest obj) {
  86             obj.x = one;
  87             AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
  88                 AtomicReferenceFieldUpdater.newUpdater
  89                 (AtomicReferenceFieldUpdaterTest.class, Integer.class, "x");
  90             assertSame(one, a.get(obj));
  91             assertTrue(a.compareAndSet(obj, one, two));
  92             assertSame(two, a.get(obj));
  93         }
  94 
  95         public void checkPrivateAccess(AtomicReferenceFieldUpdaterTest obj) {
  96             try {
  97                 AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest,Integer> a =
  98                     AtomicReferenceFieldUpdater.newUpdater
  99                     (AtomicReferenceFieldUpdaterTest.class, Integer.class, "privateField");
 100                 throw new AssertionError("should throw");
 101             } catch (RuntimeException success) {
 102                 assertNotNull(success.getCause());
 103             }
 104         }
 105     }
 106 
 107     static AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> updaterFor(String fieldName) {
 108         return AtomicReferenceFieldUpdater.newUpdater
 109             (AtomicReferenceFieldUpdaterTest.class, Integer.class, fieldName);
 110     }
 111 
 112     /**
 113      * Construction with non-existent field throws RuntimeException
 114      */
 115     public void testConstructor() {
 116         try {
 117             updaterFor("y");
 118             shouldThrow();
 119         } catch (RuntimeException success) {
 120             assertNotNull(success.getCause());
 121         }
 122     }
 123 
 124     /**
 125      * construction with field not of given type throws ClassCastException
 126      */
 127     public void testConstructor2() {
 128         try {
 129             updaterFor("z");
 130             shouldThrow();
 131         } catch (ClassCastException success) {}
 132     }
 133 
 134     /**
 135      * Constructor with non-volatile field throws IllegalArgumentException
 136      */
 137     public void testConstructor3() {
 138         try {
 139             updaterFor("w");
 140             shouldThrow();
 141         } catch (IllegalArgumentException success) {}
 142     }
 143 
 144     /**
 145      * Constructor with non-reference field throws ClassCastException
 146      */
 147     public void testConstructor4() {
 148         try {
 149             updaterFor("i");
 150             shouldThrow();
 151         } catch (ClassCastException success) {}
 152     }
 153 
 154     /**
 155      * construction using private field from subclass throws RuntimeException
 156      */
 157     public void exclude_8187607_testPrivateFieldInSubclass() {
 158         AtomicReferenceFieldUpdaterTestSubclass s =
 159             new AtomicReferenceFieldUpdaterTestSubclass();
 160         s.checkPrivateAccess();
 161     }
 162 
 163     /**
 164      * construction from unrelated class; package access is allowed,
 165      * private access is not
 166      */
 167     public void exclude_8187607_testUnrelatedClassAccess() {
 168         new UnrelatedClass().checkPackageAccess(this);
 169         new UnrelatedClass().checkPrivateAccess(this);
 170     }
 171 
 172     /**
 173      * get returns the last value set or assigned
 174      */
 175     public void testGetSet() {
 176         AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 177         a = updaterFor("x");
 178         x = one;
 179         assertSame(one, a.get(this));
 180         a.set(this, two);
 181         assertSame(two, a.get(this));
 182         a.set(this, m3);
 183         assertSame(m3, a.get(this));
 184     }
 185 
 186     /**
 187      * get returns the last value lazySet by same thread
 188      */
 189     public void testGetLazySet() {
 190         AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 191         a = updaterFor("x");
 192         x = one;
 193         assertSame(one, a.get(this));
 194         a.lazySet(this, two);
 195         assertSame(two, a.get(this));
 196         a.lazySet(this, m3);
 197         assertSame(m3, a.get(this));
 198     }
 199 
 200     /**
 201      * compareAndSet succeeds in changing value if equal to expected else fails
 202      */
 203     public void testCompareAndSet() {
 204         AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 205         a = updaterFor("x");
 206         x = one;
 207         assertTrue(a.compareAndSet(this, one, two));
 208         assertTrue(a.compareAndSet(this, two, m4));
 209         assertSame(m4, a.get(this));
 210         assertFalse(a.compareAndSet(this, m5, seven));
 211         assertNotSame(seven, a.get(this));
 212         assertTrue(a.compareAndSet(this, m4, seven));
 213         assertSame(seven, a.get(this));
 214     }
 215 
 216     /**
 217      * compareAndSet in one thread enables another waiting for value
 218      * to succeed
 219      */
 220     public void testCompareAndSetInMultipleThreads() throws Exception {
 221         x = one;
 222         final AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 223         a = updaterFor("x");
 224 
 225         Thread t = new Thread(new CheckedRunnable() {
 226             public void realRun() {
 227                 while (!a.compareAndSet(AtomicReferenceFieldUpdaterTest.this, two, three))
 228                     Thread.yield();
 229             }});
 230 
 231         t.start();
 232         assertTrue(a.compareAndSet(this, one, two));
 233         t.join(LONG_DELAY_MS);
 234         assertFalse(t.isAlive());
 235         assertSame(three, a.get(this));
 236     }
 237 
 238     /**
 239      * repeated weakCompareAndSet succeeds in changing value when equal
 240      * to expected
 241      */
 242     public void testWeakCompareAndSet() {
 243         AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 244         a = updaterFor("x");
 245         x = one;
 246         do {} while (!a.weakCompareAndSet(this, one, two));
 247         do {} while (!a.weakCompareAndSet(this, two, m4));
 248         assertSame(m4, a.get(this));
 249         do {} while (!a.weakCompareAndSet(this, m4, seven));
 250         assertSame(seven, a.get(this));
 251     }
 252 
 253     /**
 254      * getAndSet returns previous value and sets to given value
 255      */
 256     public void testGetAndSet() {
 257         AtomicReferenceFieldUpdater<AtomicReferenceFieldUpdaterTest, Integer> a;
 258         a = updaterFor("x");
 259         x = one;
 260         assertSame(one, a.getAndSet(this, zero));
 261         assertSame(zero, a.getAndSet(this, m10));
 262         assertSame(m10, a.getAndSet(this, 1));
 263     }
 264 
 265 }