1.并发包之原子类型
在多线程中保证数据的原子性,一般用法有synchronized,lock显示锁,atomic原子包,在执行多线 程程序中性能如何?JMH示例如下:
package com.mxli.concurrent.atomicdemo;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode({Mode.AverageTime,Mode.Throughput})
public class AtomicDemoJMH01 {
@State(Scope.Group)
public static class synDemo{
private int x;
public void synTest(){
synchronized (this){
x++;
}
}
}
@State(Scope.Group)
public static class LockDemo{
private int x;
private final Lock lock=new ReentrantLock();
public void lockTest(){
try {
lock.lock();
x++;
}finally {
lock.unlock();
}
}
}
@State(Scope.Group)
public static class AtomicDemo{
AtomicInteger c=new AtomicInteger();
public void atomicTest(){
c.incrementAndGet();
}
}
@Benchmark
@Group("sync")
@GroupThreads(20)
public void syncmonitor(synDemo synDemo){
synDemo.synTest();
}
@Benchmark
@Group("lock")
@GroupThreads(20)
public void lock(LockDemo LockDemo){
LockDemo.lockTest();
}
@Benchmark
@Group("atomic")
@GroupThreads(20)
public void atomicmonitor(AtomicDemo atomicDemo){
atomicDemo.atomicTest();
}
public static void main(String[] args) throws RunnerException {
final Options opts=new OptionsBuilder().include(AtomicDemoJMH01.class.getSimpleName())
.forks(1)
.warmupIterations(10)
.measurementIterations(10)
.build();
new Runner(opts).run();
}
}
执行结果如下:
Benchmark Mode Cnt Score Error Units
AtomicDemoJMH01.atomic thrpt 10 52.812 ± 1.595 ops/us
AtomicDemoJMH01.lock thrpt 10 35.348 ± 1.458 ops/us
AtomicDemoJMH01.sync thrpt 10 22.686 ± 0.473 ops/us
AtomicDemoJMH01.atomic avgt 10 0.392 ± 0.019 us/op
AtomicDemoJMH01.lock avgt 10 0.570 ± 0.040 us/op
AtomicDemoJMH01.sync avgt 10 1.012 ± 0.031 us/op
**可以看出执行效率atomic>lock>synchronized**
2.原子并发包之atomicInteger使用详解
- AtomicInteger final AtomicInteger a=new AtomicInteger(); 初始化值默认为0;
- getAndIncrement() 获取当前value的值、然后进行自增。
- incrementAndGet()先进行自增,在获取value的值。
- getAndDecrement() 获取当前value的值、在进行自减。
- decrementAndGet() 先进行自减、在获取value的值。
- compareAndSet() compareAndSet(1,12),当前值比较,如果值相等则更新为第二个参数值,返回为true,否则返回false
- weakCompareAndSet()与compareAndSet()用法一样。
- getAndAdd(int delta) getAndAdd(2)==0 如果value为0,则更新值value+delta、否则为否,基于自旋+CAS算法
- addAndGet(int delta)立即返回value+delta的值。
- set() 为value设置一个值、生成内存屏障、立即被其他线程看到
- lazyset()就是在不需要让共享变量的修改立刻让其他线程可见的时候,以设置普通变量的方式来 修改共享状态,可以减少不必要的内存屏障,从而提高程序执行的效率.
3.原子并发包之atomicInteger如何保持多线程下数据原子性
- Unsafe几乎全部由C++实现、在AtomicInteger中有一个volatile修饰的int 类型的value值
- 在Unsafe中compareAndSwapint 方法,简称CAS算法,在CAS算法中,V是内存值,旧的预期值为A,新的预期值为B,如果旧的预期值与内存值相等的时候,则更新内存中的值为B,否则什么都不做,Lock free
4.原子并发包之atomicboolean与AtomicLong
- 初始化 AtomicBoolean b=new AtomicBoolean(); 初始值为false
- compareAndSet()
- weakcompareAndSet()
- set()
- lazyset()
- getandset()与atomicInterger用法一样
- atomicboolean 通常用于多个线程操控下,某个flag开关控制,能够保证其原子性
5.原子并发包之AtomicReference
- AtomicReference 是一个泛型类,提供有参和无参两种构造函数、当使用无参数的时候,需要调用set()方法为其初始化一个value值、
- compareAndSet( )
- getandset()
1: 并发包中都是利用volatile+CAS算法无锁的操作来保证共享数据在多线程保证原子性
volatile保证各个线程对数据的可见性、
2:原子类型用自旋+CAS算法来保证线程的安全性和原子性(自旋的意思是不引起调用者睡眠,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,“自旋”一词就是因此而得名、与之相对的是互斥锁、互斥锁会进入睡眠状态、)
3:自旋的特点可以看出,会占用比较大量的资源、自旋锁比较适用于锁保持比较短的情况下使用。
ABA问题导致的原因
1:当前值为A,一个线程对当前value更新为B,
2:另外一个线程在更新A,
3:此时线程进行CAS的时候,CAS能够成功,因为值从初始值A变为B,又变为A,但是CAS并不清楚其中value发生了变化,这就是ABA的问题。
6.解决ABA问题之AtomicStampedReference
- AtomicStampedReference 其实是在AtomicReference加了一个时间戳的概念,或者称为加上一个版本号,
- AtomicStampedReference ar=new AtomicStampedReference(“hello”,1);初始化加一个版本号
- getReference()获取当前引用值
- getstamp()获取当前引用值的stamp值(版本号)
- get()获取当前引用值和版本号,可以用int数组实现
- compareAndSet()
true
false
- weakCompareAndSet() 用法与上边一样
- set()
hi----2
- AtomicLongArray、AtomicIntegerArray、AtomicReferenceArray 用法
不在一一叙述。
- AtomicIntegerFieldUpdater,AtomicBooleanFieldUpdater,AtomicReferenceFieldUpdater 原子性更新对象属性的类、
1
在使用 AtomicIntegerFieldUpdater,AtomicBooleanFieldUpdater,AtomicReferenceFieldUpdater作为更新对象的时候,需要注意,未被volatile 修饰的成员变量无法原子性更新、类变量无法原子性更新(static),无法直接访问的成员变量无法直接更新(private),final 修饰的无法更新、父类成员变量无法原子性更新
- 原子包底层依赖类sun.misc.Unsafe