1.原子类
(1).概念
一个操作是不可中断的,即要么同时执行,要么同时不执行。

(2).好处
粒度更细:原子变量可以把竞争范围缩小到变量级别。
效率更高:除了高度竞争的情况,原子类比锁具有更高的效率。

(3).分类

  • 基本类型
  • AtomicInteger
  • AtomicLong
  • AtomicBoolean
  • 数组类型
  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray
  • 引用类型
  • AtomicReference
  • AtomicStampedReference
  • AtomicMarkableReference
  • 升级类型
  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater
  • AtomicReferenceFieldUpdater
  • 累加器
  • LongAdder
  • DoubleAdder
  • 累加器
  • LongAccumulator
  • DoubleAccumulator

2.AtomicInteger
(1).getAndIncrement()和get()

public class AtomicIntegerDemo implements Runnable {
private static final AtomicInteger atomicInteger = new AtomicInteger();

public void incrementAtomic() {
atomicInteger.getAndIncrement();
}

private static volatile int basicCount = 0;

public void incrementBasic() {
basicCount++;
}

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
incrementAtomic();
incrementBasic();
}
}

public static void main(String[] args) throws InterruptedException {
AtomicIntegerDemo r = new AtomicIntegerDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("原子类的结果:" + atomicInteger.get());
System.out.println("普通变量的结果:" + basicCount);
}
}
原子类的结果:20000
普通变量的结果:19446

(2).getAndAdd()

public class AtomicIntegerDemo implements Runnable {
private static final AtomicInteger atomicInteger = new AtomicInteger();

public void incrementAtomic() {
atomicInteger.getAndAdd(2);
}

private static volatile int basicCount = 0;

public void incrementBasic() {
basicCount++;
}

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
incrementAtomic();
incrementBasic();
}
}

public static void main(String[] args) throws InterruptedException {
AtomicIntegerDemo r = new AtomicIntegerDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("原子类的结果:" + atomicInteger.get());
System.out.println("普通变量的结果:" + basicCount);
}
}
原子类的结果:40000
普通变量的结果:19788

3.AtomicArray

public class AtomicArrayDemo {

public static void main(String[] args) {
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);
Incrementer incrementer = new Incrementer(atomicIntegerArray);
Decrementer decrementer = new Decrementer(atomicIntegerArray);
Thread[] threadsIncrementer = new Thread[100];
Thread[] threadsDecrementer = new Thread[100];
for (int i = 0; i < 100; i++) {
threadsDecrementer[i] = new Thread(decrementer);
threadsIncrementer[i] = new Thread(incrementer);
threadsDecrementer[i].start();
threadsIncrementer[i].start();
}

//让子线程任务先执行完
for (int i = 0; i < 100; i++) {
try {
threadsDecrementer[i].join();
threadsIncrementer[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

for (int i = 0; i < atomicIntegerArray.length(); i++) {
if (atomicIntegerArray.get(i) != 0) {
System.out.println("发现了错误" + i);
}
System.out.println(atomicIntegerArray.get(i));
}
System.out.println("运行结束");
}
}

class Decrementer implements Runnable {
private AtomicIntegerArray array;

public Decrementer(AtomicIntegerArray array) {
this.array = array;
}

@Override
public void run() {
for (int i = 0; i < array.length(); i++) {
array.getAndDecrement(i);
}
}
}

class Incrementer implements Runnable {

private AtomicIntegerArray array;

public Incrementer(AtomicIntegerArray array) {
this.array = array;
}

@Override
public void run() {
for (int i = 0; i < array.length(); i++) {
array.getAndIncrement(i);
}
}
}

4.AtomicReference

public class SpinLock {
private AtomicReference<Thread> sign = new AtomicReference<>();

public void lock() {
Thread current = Thread.currentThread();
while (!sign.compareAndSet(null, current)) {
System.out.println("自旋获取失败,再次尝试");
}
}

public void unlock() {
Thread current = Thread.currentThread();
sign.compareAndSet(current, null);
}

public static void main(String[] args) {
SpinLock spinLock = new SpinLock();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始尝试获取自旋锁");
spinLock.lock();
System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
spinLock.unlock();
System.out.println(Thread.currentThread().getName() + "释放了自旋锁");
}
}
};
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
}
}

5.把普通变量升级为原子类

public class AtomicIntegerFieldUpdaterDemo implements Runnable {
static Candidate tom;
static Candidate peter;

public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater = AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score");

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
peter.score++;
scoreUpdater.getAndIncrement(tom);
}
}

public static class Candidate {
volatile int score;
}

public static void main(String[] args) throws InterruptedException {
tom = new Candidate();
peter = new Candidate();
AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("普通变量:" + peter.score);
System.out.println("升级后的结果:" + tom.score);
}
}
普通变量:19725
升级后的结果:20000

变量是非private和非static修饰的。

6.Adder
(1).AtomicLong计算耗时

public class AtomicLongDemo {

public static void main(String[] args) throws InterruptedException {
AtomicLong counter = new AtomicLong(0);
ExecutorService service = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
service.submit(new Task(counter));
}
service.shutdown();
while (!service.isTerminated()) {

}
long end = System.currentTimeMillis();
System.out.println(counter.get());
System.out.println("AtomicLong耗时:" + (end - start));
}

private static class Task implements Runnable {
private AtomicLong counter;

public Task(AtomicLong counter) {
this.counter = counter;
}

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.incrementAndGet();
}
}
}
}
100000000
AtomicLong耗时:3245

AtomicLong会将线程本地内存里的变量刷新到主存(flush),也会将主存里的值刷新到另一个线程的本地内存(refresh)。

(2).LongAdder计算耗时

public class LongAdderDemo {

public static void main(String[] args) throws InterruptedException {
LongAdder counter = new LongAdder();
ExecutorService service = Executors.newFixedThreadPool(20);
long start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
service.submit(new Task(counter));
}
service.shutdown();
while (!service.isTerminated()) {

}
long end = System.currentTimeMillis();
System.out.println(counter.sum());
System.out.println("LongAdder耗时:" + (end - start));
}

private static class Task implements Runnable {

private LongAdder counter;

public Task(LongAdder counter) {
this.counter = counter;
}

@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
}
}
}
100000000
LongAdder耗时:821

竞争激烈的时候,LongAdder把不同线程对应到不同Cell上进行修改,降低了冲突的概率,提高了并发性,是多段锁的理念。
每个线程会有一个自己的计数器,仅用来在自己线程内计数,以空间换时间。