java 多线程并发时有各种资源争抢问题,怎么处理资源争抢呢?
a.独占式,表现为不可重入锁或者互斥锁/独占锁/悲观锁
使用关键字synchronized,通过它可以完成代码块或函数的独占,当一个线程执行到synchronized标识的代码块时,另一个线程也执行到此处,必须等待上一个线程执行完毕释放锁才能获得锁而继续执行。
b.共享式,表现为可重入锁或者乐观锁/共享锁,
通过使用java CAS来完成共享锁的原子操作,操作是非阻塞的。
CAS原理:
sun.misc.Unsafe.compareAndSwapInt(Object paramObject, long valueOffset, int expect, int update)函数,基于硬件来实现的。函数native实现。本意为比较并交换。 4个参数,
paramObject:需要改变的对象,也就是当前封装value的对象
valueOffset:当前封装的value内存汇编偏移量,c++本地函数可以根据汇编偏移量获取真实的内存地址。
expect: 旧的预期值,一般从当前对象获取的瞬时值。
update:即将更新value的值
当且仅当旧预期值expect和valueOffset内存地址上的值相同时,将value修改为update值并返回true,否则什么都不做,并返回false。
该方法的实现位于unsafe.cpp中
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
UnsafeWrapper("Unsafe_CompareAndSwapInt");
oop p = JNIHandles::resolve(obj);
jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END
1.通过valueOffset汇编偏移量获取变量value在内存中的地址
2.然后通过Atomic::cmpxchg对比内存地址上的值和旧值,决定是否更换新值,并返回交换结果。
java实际使用的AQS java.util.concurrent.atomic包都是使用CAS实现
AtomicBoolean.class
AtomicInteger.class
AtomicIntegerArray.class
AtomicIntegerFieldUpdater.class
AtomicLong.class
AtomicLongArray.class
AtomicLongFieldUpdater.class
AtomicMarkableReference.class
AtomicReference.class
AtomicReferenceArray.class
AtomicReferenceFieldUpdater.class
AtomicStampedReference.class