原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。
int++并不是一个原子操作,所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,这就会引发错误。
为了解决这个问题,必须保证增加操作是原子的,可以通过volatile、synchronized关键字来解决并发访问的安全问题,但是这样解决太麻烦。
java.util.concurrent.atomic包提供了int和long类型的装类,它们可以自动的保证对于他们的操作是原子的并且不需要使用同步。
下面给出一个反面例子:
public class Main {
public static void main(String args[]){
//创建一个线程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//创建五个线程
Runnable runnable1=new RunnableImpl("张三",2000);
Runnable runnable2=new RunnableImpl("李四",1000);
Runnable runnable3=new RunnableImpl("王五",3000);
Runnable runnable4=new RunnableImpl("赵六",4000);
Runnable runnable5=new RunnableImpl("陈七",2000);
Runnable runnable6=new RunnableImpl("王八",2000);
Runnable runnable7=new RunnableImpl("毛九",5000);
//执行各个线程
executorService.execute(runnable1);
executorService.execute(runnable2);
executorService.execute(runnable3);
executorService.execute(runnable4);
executorService.execute(runnable5);
executorService.execute(runnable6);
executorService.execute(runnable7);
//关闭线程池
executorService.shutdown();
}
}
class RunnableImpl implements Runnable {
private static AtomicLong atomicLong=new AtomicLong(10000);
private String name; //操作人
private int x; //操作金额
RunnableImpl(String name,int x){
this.name=name;
this.x=x;
}
@Override
public void run() {
System.out.println(name+"执行了"+x+",当前余额:"+atomicLong.addAndGet(x));
}
}
运行结果如下:
张三执行了2000,当前余额:12000
王五执行了3000,当前余额:16000
赵六执行了4000,当前余额:20000
陈七执行了2000,当前余额:22000
王八执行了2000,当前余额:24000
毛九执行了5000,当前余额:29000
李四执行了1000,当前余额:13000
张三执行了2000,当前余额:12000
李四执行了1000,当前余额:13000
王五执行了3000,当前余额:16000
赵六执行了4000,当前余额:20000
陈七执行了2000,当前余额:22000
王八执行了2000,当前余额:24000
毛九执行了5000,当前余额:29000
从结果可以看出,这样的计算结果还是存在问题,原子量虽然保证了单个变量在某一个操作上的安全,但是它无法保证整个程序的安全性,下面对错误进行修正:
public class Main {
public static void main(String args[]){
//创建一个线程池
ExecutorService executorService= Executors.newFixedThreadPool(2);
//创建一个锁对象
Lock lock=new ReentrantLock(false);
//创建五个线程
Runnable runnable1=new RunnableImpl("张三",2000,lock);
Runnable runnable2=new RunnableImpl("李四",1000,lock);
Runnable runnable3=new RunnableImpl("王五",3000,lock);
Runnable runnable4=new RunnableImpl("赵六",4000,lock);
Runnable runnable5=new RunnableImpl("陈七",2000,lock);
Runnable runnable6=new RunnableImpl("王八",2000,lock);
Runnable runnable7=new RunnableImpl("毛九",5000,lock);
//执行各个线程
executorService.execute(runnable1);
executorService.execute(runnable2);
executorService.execute(runnable3);
executorService.execute(runnable4);
executorService.execute(runnable5);
executorService.execute(runnable6);
executorService.execute(runnable7);
//关闭线程池
executorService.shutdown();
}
}
class RunnableImpl implements Runnable {
private static AtomicLong atomicLong=new AtomicLong(10000);
private String name; //操作人
private int x; //操作金额
private Lock lock;
RunnableImpl(String name,int x,Lock lock){
this.name=name;
this.x=x;
this.lock=lock;
}
@Override
public void run() {
lock.lock();
System.out.println(name+"执行了"+x+",当前余额:"+atomicLong.addAndGet(x));
lock.unlock();
}
}
运行结果如下:
张三执行了2000,当前余额:12000
王五执行了3000,当前余额:15000
赵六执行了4000,当前余额:19000
陈七执行了2000,当前余额:21000
王八执行了2000,当前余额:23000
毛九执行了5000,当前余额:28000
李四执行了1000,当前余额:29000