java多线程与高并发(2) -- AQS,CAS,unsafe类
程序员文章站
2022-05-04 17:18:12
...
-
AQS
- 抽象类,相当于一个锁。维护的是volatile int state和一个FIFO线程等待队列(队列节点为线程的信息)
- 子抽象类sync
-
- sync的实现类FairSync/NonfairSync - 其他子类调用方式为引用sync作为他的一个成员变量
-
应用类
-
ReentrantLock(见锁)
-
CountDownlatch
1.new CountDownLatch(10) 初始化的时候将state值设置为10 2.await() 尝试获取锁,获取 state值是否等于0,若不等于0,则将node节点加入到等待队列中park锁住 3.可以多个线程同时进行 await() 4.CountDown() cas 将state值-1 ,如果-1之后的值==0,cas移除等待队列中的节点,释放锁,返回true 5.例子: 火箭发射: 各个线程检查(燃料,温控,设备,雷达),检查完毕进行发射。 练习:???
-
CyclicBarrier
1.CyclicBarrier barrier = new CyclicBarrier(20, () -> System.out.println("满人")); barrier.await(); 2.barrier.await(); --> 利用lock 然后condition.await() 3.party的数量进行-- 如果减到0,就执行runnable,并且释放锁condition.signalAll() 4.可循环利用,reset()之后 是和初始化的时候和线程都完成的时候的状态一样。 5.底层用的是 reentrantLock 和 condition进行控制的。
-
Semaphore
1.new Semaphore(1,true) ,如果是一个就是锁,如果是多个就是多线程限流,两个参数,另外一个参数是公平非公平 2.acquire() 获取锁,和CountDownLatch源码类似 sync.acquireSharedInterruptibly(1); 3.release() 释放锁,和CountDownLatch源码类似 sync.releaseShared(1); 4.例子:6辆车抢3个车位 5.多线程访问同一个资源,限制连接数
-
Worker
-
-
CAS
-
采用循环的方式获取锁,好处:减少线程上下文切换的消耗,缺点:循环会消耗CPU
-
源码:
1.volatile保证线程可见性 2.cas保证原子性,new对象初始化的时候,会拿到这个值的valueOffset 内存地址。 3.var1是本类对象,var2是valueOffset,通过内存地址获取var5. 4.比较的时候还是通过var1和var2获取新的值,与var5比较,如果一样跳出循环,返回var5,如果不一样重新取var5,然后在进行过compareAndSet。 5.返回var5后进行值的加减。 6.CAS(expect,update) --- > 更新到jvm中的值为 var5 + var4 返回var5在外层进行加1并返回。 7.unsafe类是rt包下 的,jvm通过此类可以直接通过源语对操作系统的内存进行操作。这个保证cas的原子性。
-
比较并交换的底层实现
unsafe.compareAndSwap ---> C++ atomic.cmpxchg ---汇编 lock_if_mp cmpxchg cmpxchg (比较并交换)是序列化的,单cpu 是原子操作,多CPU的时候, cmpxchg不是原子性的 需要前面加lock ,lock 是在执行后面指令的时候锁定一个 北桥信号。
-
手写一个自旋锁
-
1.unsafe类方式: 反射获取unsafe类 +setaccessible+valueoffset+volatile value+unsafe.cas
-
```java
public class MyCas2 {
private static Unsafe unsafe = null;//Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value1;
private static Field unsafeField = null;
static {
try {
unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
unsafe = (Unsafe) unsafeField.get(null);
valueOffset = unsafe.objectFieldOffset
(MyCas2.class.getDeclaredField("value1"));
} catch (Exception ex) { throw new Error(ex); }
}
public void lock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " come in");
while (!unsafe.compareAndSwapInt(this,valueOffset,0,1)){
}
}
public void unlock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " out");
unsafe.compareAndSwapInt(this,valueOffset,1,0);
}
public static void main(String[] args) {
MyCas2 myCas = new MyCas2();
new Thread(()->{
myCas.lock();
try {
System.out.println("EXCUTING " + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCas.unlock();
},"t1").start();
new Thread(()->{
myCas.lock();
try {
System.out.println("EXCUTING " + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCas.unlock();
},"t2").start();
}
}```
2.atomicInteger方式:把0更新为1,解锁在更新回来
public class MyCas {
private AtomicInteger atm = new AtomicInteger(0);
private AtomicReference<Thread> atomicReference= new AtomicReference<>();
public void lock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " come in");
while (!atomicReference.compareAndSet(null,thread)){
}
}
public void unlock(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " out");
atomicReference.compareAndSet(thread,null);
}
public void lock1(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " come in");
while (!atm.compareAndSet(0,1)){
}
}
public void unlock1(){
Thread thread = Thread.currentThread();
System.out.println(thread.getName() + " out");
atm.compareAndSet(1,0);
}
public static void main(String[] args) {
MyCas myCas = new MyCas();
new Thread(()->{
myCas.lock1();
try {
System.out.println("EXCUTING " + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCas.unlock1();
},"t1").start();
new Thread(()->{
myCas.lock1();
try {
System.out.println("EXCUTING " + Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
myCas.unlock1();
},"t2").start();
}
}
- unsafe类
- java 调 C/C++ 调 汇编
- 可以直接拿到类的成员变量的内存进行操作
- 可以load class 通过把class文件转化为字节数组的形式。
- cas调用的是unsafe类的方法
- cas底层
上一篇: Java 线程
下一篇: Java内存模型之重排序