多线程与高并发
- CAS compare and swap 比较并交换
- CAS 又称无锁优化 | 自旋锁 | 轻量级锁 | 乐观锁
- CAS 算法 – 个人白话理解:
cas相当于 cas(int value,int except,int newValue)方法 value-我每次获取到的值,except - 我期望我每次获取到的值,newValue - 我想把我获取到的值修改成的新值;我每一次自旋,都会比较value 与 except是否相等,如果不相等,说明value已经被其它的线程修改了,我就cas再重新试一下,如果相等了我就把变量值改成newValue。
CAS的ABA问题
ABA就是说两个线程t1,t2都读取到了i=1,但是t1 +1之后 又进行了-1 那么我t2是不知道你中间这个值是修改过,不会影响我的cas下面的操作。
解决:加版本号 检查的时候连同版本号一同检查
如果是变量是基础类型:不影响结果值,无所谓。
如果是变量是引用类型:就相当于我之前有个对象,分手之后又复合,但是中间对象经历了别的人。
Atomic*
- Atomic* 类是java原生自带的内部实现cas保证原子性的类
- Atomic 底层用的是Unsafe这个类 直接操作内存,类,实例变量,直接生成类实例。1.8版本之前是 CompareAndSet 之后是 weekCompareAndSetObject 方法
- 应用:cas解决线程同步问题
public class Thread_015 {
AtomicInteger count = new AtomicInteger(0);
void add(){
for (int i = 0; i < 10000; i++) {
count.incrementAndGet();//内部cas实现保证原子性
}
}
public static void main(String[] args) {
Thread_015 t = new Thread_015();
List<Thread> list = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
list.add(new Thread(t::add));
}
list.forEach(t1->t1.start());
list.forEach(t2-> {
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("count:"+t.count);
}
}
sychronized | Atomic* |LongAdder 效率比较
- 对比下来LongAdder效率是最高的 它内部应用了分段锁
- Atomic* 与sychronized 具体得看实际应用场景
public class Thread_016 {
static int count1=0;
static AtomicInteger count2 = new AtomicInteger(0);
static LongAdder count3 = new LongAdder();
public static void main(String[] args) throws Exception{
List<Thread> threads1 = new ArrayList<>();
Object lock = new Object();
for (int i = 0; i < 1000; i++) {
threads1.add(new Thread(()->{
for (int j = 0; j < 100000; j++) {
synchronized (lock){
count1++;
}
}
}));
}
long start1 = System.currentTimeMillis();
threads1.forEach(thread1 -> thread1.start());
threads1.forEach(thread1 -> {
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("count:"+count1+" synchronized time:"+ (System.currentTimeMillis() - start1));
List<Thread> threads2 = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
threads2.add(new Thread(()->{
for (int j = 0; j < 100000; j++) {
count2.incrementAndGet();
}
}));
}
long start2 = System.currentTimeMillis();
threads2.forEach(thread2 -> thread2.start());
threads2.forEach(thread2 -> {
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("count:"+count2+" Atomic time:"+ (System.currentTimeMillis() - start2));
List<Thread> threads3 = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
threads3.add(new Thread(()->{
for (int j = 0; j < 100000; j++) {
count3.increment();
}
}));
}
long start3 = System.currentTimeMillis();
threads3.forEach(thread3 -> thread3.start());
threads3.forEach(thread3 -> {
try {
thread3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("count:"+count3+" LongAdder time:"+ (System.currentTimeMillis() - start3));
}
}