1.原子性介绍
原子性:操作过程中不允许其他线程干扰, 可以理解为数据操作是整体,整体只有成功或失败,不允许出现部分成功部分失败,而AtomicXXX原子类本身就具有原子性。
例如:
num++在多线程下执行是不安全的, num++可以分解为
1. 读取num的值(从主内存读取)
2. 对num+1(副本内存操作)
3. 把结果赋值给num(更新主内存)
所以说num++是不具备原子性的
如果希望num++具备原子性,可以把num++的三个步骤看做一个不可拆分的整体。
只要具备了原子性,就一定是线程安全的,可以保证数据结果的准确.
2.JUC中的原子类
3.使用AtomicInteger类保证线程安全
3.1原始方式-使用synchronized同步锁解决线程安全
package com.bjsxt.test2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo1 {
private static int a = 0;
public static void main(String[] args) {
//创建固定线程线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//新建五个任务
for (int i = 0; i < 5; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
synchronized ("锁"){
//给可能会出现线程安全的代码上锁
test();
}
}
});
}
//关闭线程池
executorService.shutdown();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(a);
}
public static void test(){
//创建可能会出现线程安全问题的代码
for (int i = 0; i < 1000; i++) {
a++;
}
}
}
结果: 5000
3.2使用原子类方式-AtomicInteger方式解决
package com.bjsxt.test2;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class Demo2 {
public static void main(String[] args) {
//实例化原子类
AtomicInteger atomicInteger = new AtomicInteger(0);
//创建固定线程线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
//创建五个任务
for (int i = 0; i < 5; i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
for (int n = 0; n < 1000; n++) {
//自增一方法
atomicInteger.incrementAndGet();
}
}
});
}
executorService.shutdown();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicInteger.get());
}
}
结果: 5000
3.3原子类中的方法介绍
public class Test3 {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(0);
//先获取atomicInteger中的值, 再将值+1 num++
int i = atomicInteger.getAndIncrement();
System.out.println(i); //0
//先将值+1, 先获取atomicInteger中的值 ++num
int i2 = atomicInteger.incrementAndGet();
System.out.println(i2); //2
//先获取atomicInteger中的值, 再将值-1 num--
int i3 = atomicInteger.getAndDecrement();
System.out.println(i3); //2
//先将值-1, 先获取atomicInteger中的值 --num
int i4 = atomicInteger.decrementAndGet();
System.out.println(i4); //0
//先获取atomicInteger中的值, 再+指定的值
int i5 = atomicInteger.getAndAdd(10);
System.out.println(i5); //0
先+指定的值, 先获取atomicInteger中的值
int i6 = atomicInteger.addAndGet(20);
System.out.println(i6); //30
int i7 = atomicInteger.getAndAdd(-5);
System.out.println(i7); //30
int i8 = atomicInteger.addAndGet(-10);
System.out.println(i8); //15
//改变atomicInteger中的值
atomicInteger.set(100);
int andSet = atomicInteger.getAndSet(200);
System.out.println(andSet); //100
//先获取atomicInteger中的值
int i1 = atomicInteger.get();
System.out.println(i1); //200
}
}
3.4AtomicInteger底层实现原理
原子类AtomicInteger底层使用的是volatile 和 CAS 实现。
注意:
* AtomicInteger: 天生就是线程安全的 在使用原子类的时候 不许要额外加锁
* 除非操作的不是原子类