这个是在学习工作中的一些总结,若有不对之处欢迎大家指出。侵删!
需要源码联系QQ:1352057131
得之在俄顷,积之在平日。
原子类的作用
原子类和锁的作用类似,都是为了保证并发情况下的线程安全,不过原子类相比于锁有一定的优势:
粒度更细:原子变量可以把竞争范围缩小到变量级别。
效率更高:使用原子类的效率比使用锁的效率更高,但是高竞争下的情况除外。
原子类概览
Atomic*基本类型原子类
AtomicInteger常用方法
//获取当前的值并加上预期的值
atomicInteger.getAndAdd(int value);
//获取当前值
atomicInteger.get();
//获取当前值并自减
atomicInteger.getAndDecrement();
//获取当前值并自增
atomicInteger.getAndIncrement();
//获取当前值并设置新值
atomicInteger.getAndSet(int value);
//如果输入的值等于预期值,则以原子的方式将该值设置为输入值(update)
atomicInteger.compareAndSet(int value,int update);
AtomicInteger示例
public class AtomicTest implements Runnable{
private static AtomicInteger atomicInteger = new AtomicInteger(0);
private static int a = 0;
public static void Atomicadd(){
atomicInteger.getAndIncrement();
}
public static void add(){
a++;
}
public static void main(String[] args) throws InterruptedException {
Thread thread0 = new Thread(new AtomicTest());
Thread thread1 = new Thread(new AtomicTest());
thread0.start();
thread1.start();
thread0.join();
thread1.join();
System.out.println("atomicInteger="+atomicInteger);
System.out.println("a="+a);
}
@Override
public void run() {
for (int i = 0; i <100000 ; i++) {
Atomicadd();
add();
}
}
}
运行结果:
从图中可以看出AtomicInteger是线程安全的
Atomic*Array数组类型原子类
AtomicIntegerArray示例
public class AtomicTest{
//声明长度为100的AtomicIntegerArray
private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(100);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.submit(new Add(atomicIntegerArray));
executorService.submit(new Dec(atomicIntegerArray));
Thread.sleep(1000);
executorService.shutdown();
for (int i = 0; i <atomicIntegerArray.length() ; i++) {
if (atomicIntegerArray.get(i)!=0){
System.out.println("发现不等于0的数");
}
}
System.out.println("执行完毕");
}
}
class Add implements Runnable{
private AtomicIntegerArray atomicIntegerArray;
public Add(AtomicIntegerArray atomicIntegerArray) {
this.atomicIntegerArray = atomicIntegerArray;
}
@Override
public void run() {
for (int i = 0; i < atomicIntegerArray.length(); i++) {
//加1
atomicIntegerArray.getAndIncrement(i);
}
}
}
class Dec implements Runnable{
private AtomicIntegerArray atomicIntegerArray;
public Dec(AtomicIntegerArray atomicIntegerArray) {
this.atomicIntegerArray = atomicIntegerArray;
}
@Override
public void run() {
for (int i = 0; i < atomicIntegerArray.length(); i++) {
//减1
atomicIntegerArray.getAndDecrement(i);
}
}
}
Atomic*Reference引用类型原子类
AtomicReference示例
Atomic*FieldUpdater升级类型原子类
AtomicIntegerFieldUpdater示例
public class AtomicIntegerFieldUpdaterTest implements Runnable{
//第一个参数为类 第二个参数为要升级的变量名
AtomicIntegerFieldUpdater<User> aifu = AtomicIntegerFieldUpdater.newUpdater(User.class,"number");
static User tom = new User();
static User tony = new User();
public static void main(String[] args) throws InterruptedException {
AtomicIntegerFieldUpdaterTest aifut = new AtomicIntegerFieldUpdaterTest();
for (int i = 0; i < 1000; i++) {
Thread thread0 = new Thread(aifut);
Thread thread1 = new Thread(aifut);
thread0.start();
thread1.start();
thread0.join();
thread1.join();
}
System.out.println("tom"+tom.number);
System.out.println("tony"+tony.number);
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
tom.number++;
aifu.getAndDecrement(tony);
}
}
static class User{
volatile int number;//分数
}
}
Adder累加器
为什么要使用Adder
高并发下LongAdder比AtomicLong效率高,不过本质是空间换时间。
竞争激烈的时候,LongAdder把不同的线程对应到不同的Cell上进行修改,降低了冲突的概率,事多段锁的理念,提高了并发性。
LongAdder示例
public class AdderTest implements Runnable{
private static LongAdder longAdder = new LongAdder();
public void Adder_Add(){
longAdder.increment();
}
@Override
public void run() {
Adder_Add();
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
for (int i = 0; i <10000 ; i++) {
executorService.submit(new AdderTest());
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
System.out.println(longAdder);
}
LongAdder与AtomicLong性能对比
LongAdder:
```java
public class AdderTest implements Runnable{
private static LongAdder longAdder = new LongAdder();
public void Adder_Add(){
for (int i = 0; i < 1000; i++) {
longAdder.increment();
}
}
@Override
public void run() {
Adder_Add();
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i <100000 ; i++) {
executorService.submit(new AdderTest());
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start));
}
}
AtomicLong:
public class AtomicLongTest implements Runnable{
private static AtomicLong atomicLong = new AtomicLong(0);
@Override
public void run() {
for (int i = 0; i <1000 ; i++) {
atomicLong.getAndIncrement();
}
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i <100000 ; i++) {
executorService.submit(new AtomicLongTest());
}
executorService.shutdown();
while (!executorService.isTerminated()){
}
long end = System.currentTimeMillis();
System.out.println("执行时间:"+(end-start));
}
}
从运行结果可以看出LongAdder的效率明显要高很多,原因如下:
AtomicLong每次加法都要flush和refresh导致很耗费资源
从图中可以看出AtomicLong每次加法都要做同步,在高并发的情况下会导致冲突比较多因此效率下降,而LongAdder每个线程都会有自己的计数器,仅用来在自己线程内计数,这样就不会受到其他线程计数器的干扰。如下图
从图中可以看出,第一个线程的计数器数值,也就是str’,为1的时候,可能线程2的计数器ctr”的数值已经是3了,他们之间并不存在竞争关系,所以在加和的过程中根本不需要同步机制,也不需要flush和refresh。也没有公共的counter来计数。只是到最后sum的时候才会同步将所有的数值累加起来 。
适用场景
适用于统计求和计数的场景,而且LongAdder基本只提供了add方法,AtomicLong还具有cas操作。