Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
1. 分类:
1.1 基本类型
1.1.1 AtomicInteger 整型原子类
常见用法:
/*** 此方法是AtomicInteger原子类的测试类*/public class AtomicIntegerTest {public static void main(String[] args) {AtomicInteger num = new AtomicInteger(10);/*** 获取当前值*/int n1 = num.get();System.out.println("n1 --> " + n1 + " and now num --> " + num);/*** 获取当前值 并设置新的值*/int n2 = num.getAndSet(20);System.out.println("n2 --> " + n2 + " and now num --> " + num);/*** 获取当前值 并自增* n3 --> 20 and now num --> 21*///int n3 = num.getAndIncrement();int n3 = num.incrementAndGet();System.out.println("n3 --> " + n3 + " and now num --> " + num);/*** 获取当前值 并自减*/int n4 = num.getAndDecrement();System.out.println("n4 --> " + n4 + " and now num --> " + num);/*** 获取当前值 并加相应值*/int n5 = num.getAndAdd(10);System.out.println("n5 --> " + n5 + " and now num --> " + num);/*** 如果输入的数值等于预期值,则以原子方式将该值设置为输入值(update)*/boolean b = num.compareAndSet(30, 5);System.out.println("b --> " + b + " and now num --> " + num);}}// ---结果------n1 --> 10 and now num --> 10n2 --> 10 and now num --> 20n3 --> 21 and now num --> 21n4 --> 21 and now num --> 20n5 --> 20 and now num --> 30b --> true and now num --> 5
多线程环境保证线程安全:
// volatile + synchronized 结合保证线程安全
public class MutiThreadDemo {
/**
* volatile关键字表示 线程间共享
*/
private volatile int count = 0;
/**
* 方法上锁
*/
public synchronized void increamentCount() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
MutiThreadDemo counter = new MutiThreadDemo();
int workCount = 50000;
ExecutorService executor = Executors.newFixedThreadPool(10);
long start = System.currentTimeMillis();
for (int i = 0; i < workCount; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.increamentCount();
}
};
executor.execute(runnable);
}
// 关闭启动线程,执行未完成的任务
executor.shutdown();
// 等待所有线程完成任务,完成后才继续执行下一步
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("执行结果:count=" + counter.getCount());
}
}
// ----------------------------------
/**
* 多线程环境下使用AtomicInter原子类
*/
public class MutiThreadUseAtomicDemo {
private AtomicInteger count = new AtomicInteger();
public void increamentCount() {
count.incrementAndGet();
}
public int getCount() {
return count.get();
}
public static void main(String[] args) throws InterruptedException {
MutiThreadUseAtomicDemo counter = new MutiThreadUseAtomicDemo();
int workCount = 50000;
ExecutorService executor = Executors.newFixedThreadPool(10);
long start = System.currentTimeMillis();
for (int i = 0; i < workCount; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
counter.increamentCount();
}
};
executor.execute(runnable);
}
// 关闭启动线程,执行未完成的任务
executor.shutdown();
// 等待所有线程完成任务,完成后才继续执行下一步
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("执行结果:count=" + counter.getCount());
}
}
AtomicInteger线程安全原理分析:
AtomicInteger主要是利用CAS + volatile + native方法来保证原子操作的。
在AtomicInteger原子类中, getAndIncrement方法实际上调的是UnSafe类中的方法(Java中的Unsafe类为我们提供了类似C++手动管理内存的能力)
PS:
this —> AtomicInteger实例
unsafe —-> 后门类, 用于直接操作内存中的数据.
valueOffset —> 数据在内存中地址偏移量.
value —> 要修改的值, volatile保证了可见性
UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
拿到对象的偏移量, 可以定位到在内存中的值, 接下来执行getAndAddInt方法.
参数1: 当前对象, 参数2: 对象的偏移量, 参数3:要增加的值。compareAndSwapInt使用原理是CAS。
AtomicLong 长整型原子类(同上)
AtomicBoolean 布尔型原子类
1.2 数组类型原子类
AtomicIntegerArray:整形数组原子类
/**
* 整形数组原子类使用
*/
public class AtomicIntegerArrayTest {
public static void main(String[] args) {
int[] nums = {1,2,3,4,5,6};
AtomicIntegerArray arrays = new AtomicIntegerArray(nums);
for (int i = 0; i < arrays.length(); i++) {
/**
* 获取 index=i 位置元素的值
*/
System.out.print(arrays.get(i) + " ");
}
System.out.println("\n---------------");
/**
* 返回 index=i 位置的当前的值,并将其设置为新值:newValue
*/
int arr0 = arrays.getAndSet(0, 6);
System.out.println("arr0 -> " + arr0 + " arrays[0] -> " + arrays.get(0));
/**
* 返回 index=i 位置的当前的值,并将其add值
*/
int arr1 = arrays.getAndAdd(1, 6);
System.out.println("arr1 -> " + arr1 + " arrays[1] -> " + arrays.get(1));
/**
* 返回 index=i 位置的当前的值,并将其+1
*/
int arr2 = arrays.getAndIncrement(2);
System.out.println("arr2 -> " + arr2 + " arrays[2] -> " + arrays.get(2));
/**
* 返回 index=i 位置的当前的值,并将其-1
*/
int arr3 = arrays.getAndIncrement(3);
System.out.println("arr3 -> " + arr3 + " arrays[3] -> " + arrays.get(3));
boolean success = arrays.compareAndSet(4, 5, 10);
System.out.println("success -> " + success + " arrays[4] -> " + arrays.get(4));
for (int i = 0; i < arrays.length(); i++) {
System.out.print(arrays.get(i) + " ");
}
}
}
