import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 原子操作:不可被打断的一些列操作,32位多处理器主要通过对总线和缓存加锁保证原子性。
* 首先要保证原子性,需要处理器对于数据的处理要保证原子性,当一个处理器读取内存中的数据时,对于其他处理器是内存地址不可访问,即对于该内存地址加锁。
* 1,总线锁:当一个处理器读取内存中的数据时,对于共享内存的总线加Lock指令,其他处理器被阻塞,但这样其他处理器不能访问其他共享内存的数据。
* 2, 缓存锁:频繁使用的数据会缓存在L1、L2、L3缓存中,缓存一致性会阻止同时修改两个处理器缓存的同一个内存数据。通过回写改变内存的方式,使得另一个处理器写失败。
* 有一部分情况不能使用缓存锁定:1 , 处理器不支持缓存锁定 。 2 , 数据不能加载进处理器缓存。
* 对于一些inter指令,Inter处理器提供了很多LOCK前缀的指令,通过在指令前面加LOCK指令,会对缓存加锁,保证其他处理器不能同时访问数据。
* java中可以通过锁和循环CAS的方式来实现原子操作,java current包中的类大多是通过CAS方式实现的,CAS是基于处理器CMPXCHG指令。
* 在java中除了偏向锁(锁的等级分为无锁、偏向锁、轻量级锁、重量级锁),其他锁的方式都是通过CAS方式实现的。
* AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作,对于这个对象的操作的原子性。
* 原子操作会有ABA的问题,当CompareAndSet时,比较的变量会有A-B-A的过程,则为false。通过添加版本号,变为A1-B2-A3。
* CAS是通过循环操作比较的,无限循环会大量消耗cpu。CAS一次只能操作一个变量,现在通过atomicReference,可以原子改变一个对象状态。
* AQS是一种思想,线程安全的集合用到了AQS思想,锁的实现是通过CAS实现的。通过AQS实现ReetrantLock的lock和unlock的过程,具体的lock获取,unlock通过CAS实现的。
* AQS - abstractQueueSynchronized,通过队列的方式管理lock,lock的实现通过CAS具体实现的。
* @author pc
*
*/
public class AtomicTest {
public AtomicInteger atomicI = new AtomicInteger(0);// 使用CAS操作,保证原子性。
public int i = 0;
public void unSafe(){
i++;
}
public void safeCount(){
for(;;){
int i = atomicI.get();
boolean flag = atomicI.compareAndSet(i, ++i);
if (flag){
break;
}
}
}
public static void main(String[] args){
final AtomicTest test = new AtomicTest();
/**
* final 的作用保证在多线程中的不可变性,即可以在多线程中直接使用
* final 关键字提高了性能,java应用和JVM都会缓存final关键字的变量
*
*/
List<Thread> list = new ArrayList<Thread>();
for(int j = 0; j < 1000; j++){
Thread t = new Thread(new Runnable(){
public void run(){
test.unSafe();
test.safeCount();
}
});
list.add(t);
}
for(Thread thread : list){
thread.start();
}
System.out.println(test.i);// 不能保证原子性,在同一时刻可能有多个线程修改i这个变量。
System.out.println(test.atomicI.get());// 保证了原子性,输出1000,在同一时刻只有一个线程修改这个atomicInteger这个变量。
}
}
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 原子操作:不可被打断的一些列操作,32位多处理器主要通过对总线和缓存加锁保证原子性。
* 首先要保证原子性,需要处理器对于数据的处理要保证原子性,当一个处理器读取内存中的数据时,对于其他处理器是内存地址不可访问,即对于该内存地址加锁。
* 1,总线锁:当一个处理器读取内存中的数据时,对于共享内存的总线加Lock指令,其他处理器被阻塞,但这样其他处理器不能访问其他共享内存的数据。
* 2, 缓存锁:频繁使用的数据会缓存在L1、L2、L3缓存中,缓存一致性会阻止同时修改两个处理器缓存的同一个内存数据。通过回写改变内存的方式,使得另一个处理器写失败。
* 有一部分情况不能使用缓存锁定:1 , 处理器不支持缓存锁定 。 2 , 数据不能加载进处理器缓存。
* 对于一些inter指令,Inter处理器提供了很多LOCK前缀的指令,通过在指令前面加LOCK指令,会对缓存加锁,保证其他处理器不能同时访问数据。
* java中可以通过锁和循环CAS的方式来实现原子操作,java current包中的类大多是通过CAS方式实现的,CAS是基于处理器CMPXCHG指令。
* 在java中除了偏向锁(锁的等级分为无锁、偏向锁、轻量级锁、重量级锁),其他锁的方式都是通过CAS方式实现的。
* AtomicReference类来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行CAS操作,对于这个对象的操作的原子性。
* 原子操作会有ABA的问题,当CompareAndSet时,比较的变量会有A-B-A的过程,则为false。通过添加版本号,变为A1-B2-A3。
* CAS是通过循环操作比较的,无限循环会大量消耗cpu。CAS一次只能操作一个变量,现在通过atomicReference,可以原子改变一个对象状态。
* AQS是一种思想,线程安全的集合用到了AQS思想,锁的实现是通过CAS实现的。通过AQS实现ReetrantLock的lock和unlock的过程,具体的lock获取,unlock通过CAS实现的。
* AQS - abstractQueueSynchronized,通过队列的方式管理lock,lock的实现通过CAS具体实现的。
* @author pc
*
*/
public class AtomicTest {
public AtomicInteger atomicI = new AtomicInteger(0);// 使用CAS操作,保证原子性。
public int i = 0;
public void unSafe(){
i++;
}
public void safeCount(){
for(;;){
int i = atomicI.get();
boolean flag = atomicI.compareAndSet(i, ++i);
if (flag){
break;
}
}
}
public static void main(String[] args){
final AtomicTest test = new AtomicTest();
/**
* final 的作用保证在多线程中的不可变性,即可以在多线程中直接使用
* final 关键字提高了性能,java应用和JVM都会缓存final关键字的变量
*
*/
List<Thread> list = new ArrayList<Thread>();
for(int j = 0; j < 1000; j++){
Thread t = new Thread(new Runnable(){
public void run(){
test.unSafe();
test.safeCount();
}
});
list.add(t);
}
for(Thread thread : list){
thread.start();
}
System.out.println(test.i);// 不能保证原子性,在同一时刻可能有多个线程修改i这个变量。
System.out.println(test.atomicI.get());// 保证了原子性,输出1000,在同一时刻只有一个线程修改这个atomicInteger这个变量。
}
}