Java多线程---了解AQS

AQS (abstractQueuedSynchroizer)

  • 抽象队列同步器

synchronized 1.5的改进

  • synchronized是重量级锁。但是在java1.5后对synchronized进行了改进
  • synchronized锁在初始是偏向锁,当有其他线程竞争时升级成为轻量级锁,(多数情况下是自旋锁) 当自旋超过10次将会升级成为重量级锁

为什么synchronized是重量级锁
synchronized锁 需要jvm调用操作系统(OS),然后需要cpu在用户态(user mode)跟内核态(kernel mode)来回切换. 比较耗时,所以叫重量级锁
lock锁只需要在jvm中就可以实现锁了,所以是轻量级的

乐观锁cas和悲观锁synchronized锁适合于哪种情况

  • 如果在超高并发,锁的竞争特别激烈的情况下,适合于悲观锁。(否则自旋锁一直自旋,消耗cpu)
  • 如果并发不高,竞争不激烈,cas比较合适。
    lock的实现类 依赖于 AQS
    AQS 依赖于一个 先进先出的等待队列 CLH队列

volatile 关键字作用

保证一个线程修改了某个变量的值后,该新值对其他线程是立即可见
禁止进行指令重排序
不保证原子性

使用场景
  • 在双重检查单例模式的那里,对象应该加 volatile关键字。
    原因: jvm在内部对对象进行初始化的操作时的步骤为:1.开辟空间 2.空间初始化 3.init赋值 4.将地址赋值给变量。
    在实际操作中,这四个步骤的执行顺序可能 2执行完成后,先执行了4,然后才执行3.
    在多线程的环境下,假如 在执行完4后还没来得急执行3. 另一个线程进入,判断 INSTANCE==null 错误,返回INSTANCE对象,但是对象还没有执行第3步,是个半成品对象。则出现问题。
public class Singleton1 {
    //需要加上volatile,为了防止指令重排
    private static volatile Singleton1 INSTANCE;
    private Singleton1(){
    }
    public  Singleton1 newInstance(){
        if(INSTANCE==null) {
            synchronized (Singleton1.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton1();
                }
            }
        }
        return INSTANCE;
    }
}

自实现lock锁 采用 AQS锁机制

  • 自定义的lock锁可以将AQS锁作为内部类 来实现乐观锁操作
  • AQS内部有一个volatile int型的变量state 用来当锁变量(初始值为0),和一个先进先出的等待队列CLH
  • 上锁:lock 锁中的lock 方法 调用 内部类的acquire方法,acquire调用 tryAcquire方法(模板设计模式)
  • tryAcquire 调用cas算法,自旋等待 锁被释放。 得到锁后,上锁(state变为1),并设为互斥锁 返回true
  • 释放锁:lock锁的unlock方法 调用内部类的release方法, release调用tryRelease方法
  • tryRelease判断当前线程是否占有锁,如果占有锁,则释放,并把state再设回 0;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class AQSLock implements Lock {
    private Sync sync=new Sync();
    @Override
    public void lock() {
        //调用 acquire方法, 是模板设计模式
        sync.acquire(1);
    }

    @Override
    public void unlock() {
        sync.release(1);
    }
    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    @Override
    public boolean tryLock() {
        return false;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }


    public class Sync extends AbstractQueuedSynchronizer{
        /**
         * 当新线程来了后,调用此方法 竞争锁资源
         * @param arg
         * @return
         */
        @Override
        protected boolean tryAcquire(int arg) {
            //AQS内部实现是 一个int变量state作为锁,初始值为0, 和一个先进先出等待队列 CLH
            if(compareAndSetState(0,1)){ //如果锁变量由0变为了1。这里调用的是CAS算法
                setExclusiveOwnerThread(Thread.currentThread());// 设置为互斥锁
                return true;
            }
            return false;
        }
        /**
         * 尝试释放锁资源
         * @param arg
         * @return
         */
        @Override
        protected boolean tryRelease(int arg) {
            assert arg==1;// arg必须是1 如果不是1则认为不对
            //如果当前线程不持有锁,则抛出异常
            if(!isHeldExclusively()) throw new IllegalMonitorStateException();
            //持有锁则释放
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        /**
         * 返回当前占有锁的线程是不是当前线程(当前线程是不是持有锁)
         * @return
         */
        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread() ==Thread.currentThread();
        }
    }
    @Override
    public Condition newCondition() {
        return null;
    }
}

测试类:

import java.util.concurrent.locks.Lock;

public class TestLock {

    public static int m=0;
    public static void main(String[] args) throws InterruptedException {
        Thread[] thread =new Thread[100];
        Lock lock=new AQSLock();
        for (int i = 0; i <100 ; i++) {
            thread[i]=new Thread(()->{
                try {
                    lock.lock();
                    for (int j = 0; j < 100; j++) {
                        m++;
                    }
                }finally {
                    lock.unlock();
                }
            });
        }
        for (Thread t : thread) {
            t.start();
        }
        for (Thread t : thread) {
            t.join();
        }
        System.out.println(m);
    }
}
assert 关键字

assert boolean表达式; 正确 继续执行 ,错误 抛出异常。

CountDownLatch

  • 使用 countDownLatch 代替join方法 做门栓。
  • CountDownLatch latch=new CountDownLatch(100);
  • 也是基于 AQS来实现的
  • 内部使用了一个 共享锁
  • 调用 countDown方法 使值减一。 当值为1时打开锁。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;

public class TestLock {

    public static int m=0;
    public static void main(String[] args) throws InterruptedException {
        Thread[] thread =new Thread[100];
        CountDownLatch latch=new CountDownLatch(100);
        Lock lock=new AQSLock();
        for (int i = 0; i <100 ; i++) {
            thread[i]=new Thread(()->{
                try {
                    lock.lock();
                    for (int j = 0; j < 100; j++) {
                        m++;
                    }
                }finally {
                    lock.unlock();
                }
            });
            latch.countDown();
        }
        for (Thread t : thread) {
            t.start();
        }
        latch.await();
//        for (Thread t : thread) {
//            t.join();
//        }
        System.out.println(m);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值