即使我们使用volitile,也无法保证多线程访问共享变量的原子性,如下:
package com.jeff.base.sync007; /** * * volatile关键字不具备synchronized关键字的原子性(同步) * @author jeff * */ public class VolatileNoAtomic extends Thread{ private static volatile int count; //private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for (int i = 0; i < 1000; i++) { count++ ; //count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100]; for (int i = 0; i < 10; i++) { arr[i] = new VolatileNoAtomic(); } for (int i = 0; i < 10; i++) { arr[i].start(); } } }
启动10个线程,对volitile修饰的count静态变量进行+1,最后的结果并不是10000,说明volitile并不保证同步,也就是无法原子性。
打印结果:
1048 1048 3012 4012 4048 5048 6048 7048 8595 9036
所以我们可以使用AutomicInteger来解决这个问题:
package com.jeff.base.sync007; import java.util.concurrent.atomic.AtomicInteger; /** * * volatile关键字不具备synchronized关键字的原子性(同步) * @author jeff * */ public class VolatileNoAtomic extends Thread{ //private static volatile int count; private static AtomicInteger count = new AtomicInteger(0); private static void addCount(){ for (int i = 0; i < 1000; i++) { //count++ ; count.incrementAndGet(); } System.out.println(count); } public void run(){ addCount(); } public static void main(String[] args) { VolatileNoAtomic[] arr = new VolatileNoAtomic[100]; for (int i = 0; i < 10; i++) { arr[i] = new VolatileNoAtomic(); } for (int i = 0; i < 10; i++) { arr[i].start(); } } }
打印结果,最终得到10000:
1927 2000 3000 4090 5000 6391 7000 9018 9113 10000
多个addAndGet在一个自定义的方法内部是非原子的,需要同步对象锁修饰:
package com.jeff.base.sync007; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; /** * //多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰, * 保证4个addAndGet整体原子性 * @author jeffSheng * */ public class AtomicUse { private static AtomicInteger count = new AtomicInteger(0); /**synchronized*/ public synchronized int multiAdd(){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count.addAndGet(1); count.addAndGet(2); count.addAndGet(3); count.addAndGet(4); //+10 return count.get(); } public static void main(String[] args) { final AtomicUse au = new AtomicUse(); List<Thread> ts = new ArrayList<Thread>(); for (int i = 0; i < 100; i++) { ts.add(new Thread(new Runnable() { @Override public void run() { System.out.println(au.multiAdd()); } })); } for(Thread t : ts){ t.start(); } } }