鉴于本人对知识理解的深度有限,且尚需更多地学习,如有错误和不足欢迎指正批评,下面我们就来聊聊关于java从入门到精通练习题答案在哪?接下来我们就一起去了解一下吧!
java从入门到精通练习题答案在哪
鉴于本人对知识理解的深度有限,且尚需更多地学习,如有错误和不足欢迎指正批评。
概念CAS(compareAndSwap)是一条并发原语。在Java中的体现就是Unsafe下的各个方法。
CAS与自旋锁Java Unsafe中的getAndAddInt方法采用自旋锁实现变量原子增加。
// sun.misc.Unsafe#getAndAddInt
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {// 自旋锁
var5 = this.getIntVolatile(var1, var2);// 获取var1对象var2偏移位置的值
} while(!this.compareAndSwapInt(var1, var2, var5, var5 var4));
return var5;
}
// sun.misc.Unsafe#compareAndSwapInt
// var1要修改的对象、var2内存偏移位置、var4期望值、var5赋予值
// 修改成功返回true,没成功返回false
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
总的来说,CAS就是通过与预期值的比较来确定是否进行修改。
手写自旋锁
import java.util.concurrent.atomic.AtomicReference;
public class SpinLock {
// 原子引用保证锁
AtomicReference<Thread> ar = new AtomicReference<>();
// 加锁
public void lock() {
while (ar.compareAndSet(null, Thread.currentThread()));
}
// 解锁
public void unlock() {
ar.compareAndSet(Thread.currentThread(), null);
}
//##################################################################
// 测试变量
static volatile int i = 0;
// 自旋锁测试函数
public static void test() {
SpinLock spinLock = new SpinLock();
new Thread(()->{
spinLock.lock();
i ;
spinLock.unlock();
}).start();
new Thread(()->{
spinLock.lock();
i ;
spinLock.unlock();
}).start();
}
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j < 1000; j ) {
test();
}
Thread.sleep(3000);
System.out.println(i);
}
}
CAS的优点
- 不用阻塞线程,并发性比synchronized更好。
- 避免了线程在用户态和内核态直接切换,省去切换的时间,一次阻塞和唤醒操作就需要两次切换。
CAS的缺点
- 只能保证某一个对象的原子性,并不能保证几个对象或一个线程同步操作。
- 如果比较交换不成功,会一直进行比较,会给CPU带来很大的开销。
- 存在ABA问题。
ABA问题
当一个线程拿到一个真实值准备进行比较交换,但是在这个时候,这个真实值被其他线程更改了,又被另一个线程改了回来,这个再去比较交换。虽然是成功了,但是,对于这个线程拿到真实值到比较交换的过程期间,内存中值的变化细节对于这个线程是不可见的。
解决思路
可以通过数据版本号来解决ABA问题。
AtomicStampedReference、AtomicStampedReference、AtomicReference等类使用了类似于版本的方法解决了这个问题,本质是时间戳原子引用。
AtomicStampedReference悲观CAS、AtomicReference乐观CAS
,