定义:当多个线程访问某各类时,不管运行时环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中,不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全的
原子性:提供了互斥访问,同一个时刻只能有线程对他进行操作
可见性:一个线程对主内存的修改可以及时的被其他线程观察到
有序性:一个线程观察其他线程中的指令顺序,由于指令重排序的存在,该观察结果一般杂乱无序
举个例子
package com.mmall.concurrency.example.atomic;
import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
@ThreadSafe
public class AtomicExample1 {
// 请求总数
public static int clientTotal = 5000;
// 同时并发执行的线程数
public static int threadTotal = 200;
public static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
log.error("exception", e);
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
log.info("count:{}", count.get());
}
private static void add() {
count.incrementAndGet();
// count.getAndIncrement();
}
}
这段代码不论怎么执行都是5000,因为
count.incrementAndGet();
Atomic用了CAS实现了原子性.
打开这个方法
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
再打getAndAddInt方法
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
compareAndSwapInt()是native方法,用C实现的
var1代表传过来的对象,也就是这个例子的count;var2是当前的值,比如执行4+1的操作,那么var2就是4,var3就是1
this.compareAndSwapInt(var1, var2, var5, var5 + var4)代表如果var2 = var5的情况下,输出var5+var4,否则再取一次。
好比var2是2,但是另一个线程运行了,让var2的主存变成3,即var5是3,compareAndSwapInt方法中var2 不等与 vae5,
返回false,再取一次。
这次var2=var5,即底层的值和期望的值完全相同,就执行var5 =var5+var4,再把var5传回去