Java成神之路——重入锁、公平非公平锁、自旋锁、读写锁

你知道的Java锁有哪些? synchronized?Lock?它们又有什么区别?锁可分为哪些种类?锁是如何实现的?


公平与非公平锁

公平锁与非公平锁的区别体现在锁造成阻塞时的排队机制,公平锁按申请锁顺序排队等待获取锁,而非公平并不是按照申请顺序,有可能后申请的线程先获取到锁。

常用到的ReentrantLock 在创建的时候可以指定锁机制是公平还是非公平,默认非公平。synchronized也是非公平的

    public ReentrantLock() {
        sync = new NonfairSync();
    }

    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }


可重入锁

synchronized,ReentrantLock,都是可重入锁,在同一线程在外层方法获取锁的时候,在进入内层方法会自动获取锁,也就是说线程可以进入任何一个它已经拥有的锁所同步的代码块,即表示可重新反复进入的锁,但仅限于当前线程;

// 线程可以进入任何一个它已经拥有的锁所同步的代码块
public synchronized void method1(){
	// 访问另一个同步方法,自动获取锁
	method2();
}

public synchronized void method2(){
}

Lock锁,可重入示例加几次锁,要记得释放几次

    private ReentrantLock lock = new ReentrantLock();
    public void method1(){
        try {
            lock.lock();
            // 可重入,可以进入任何一个它已经拥有的锁所同步的代码
            method2();
        }finally {
            lock.unlock();
        }

    }
    public void method2(){
        try {
            lock.lock();
        }finally {
            lock.unlock();
        }

    }

自旋锁

什么是自旋锁,通过名字就可以猜到大概,通过unsafe+volatile自旋(while)的方式来"阻塞代码"

尝试获取锁的线程不会阻塞,而是采用循环的方式去尝试获取锁,这样的好处是可以减少线程上下文切换,缺点就是消耗cpu

// Unsafe 类中的一处自旋锁
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
        	// 拿到原有的值
            var5 = this.getIntVolatile(var1, var2);
            // 尝试进行替换,如果替换成功返回,否则一直尝试
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
自己实现一个自旋锁
// 思考一下这个锁是可重入还是不可重入
public class MyLock {
   
    private AtomicReference<Thread> reference = new AtomicReference<>();
    public void lock(){
        Thread thread = Thread.currentThread();
        // 如果当前引用中有thread,那么说明在加锁中,其他线程自旋等待
        while(!reference.compareAndSet(null,thread)){
            System.out.println(thread.getName()+"尝试加锁");
        }
    }
    public void unlock(){
        Thread thread = Thread.currentThread();
        // 解锁,如果当前线程是自己引用置为null
        reference.compareAndSet(thread,null);
        System.out.println(thread.getName()+"解锁");
    }
}


独占锁/共享锁/互斥锁

独占锁

指该锁一次只能被一个线程锁持有。对ReentrantLock和Synchronized而言都是独占锁。

共享锁

该锁可以被多个线程持有

读写锁

ReentrantReadWriteLock 其读锁就是共享锁,写锁就是共享锁;读写,写读,写写的过程互斥,互斥锁。

示例:

public class MyData {

    private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private volatile Map<String, Object> map = new HashMap<>();

    public Object get(String key) {
        // 添加读锁
        readWriteLock.readLock().lock();
        Object o = null;
        try {

            System.out.println(Thread.currentThread().getName() + "读取");
            o = map.get(key);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "读取完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.readLock().unlock();
        }
        return o;
    }


    public void put(String key, Object value) {
        // 添加写锁
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "写入");
            map.put(key, value);
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "写入完成");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public static void main(String[] args) {
        MyData m = new MyData();

        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(() -> {
                m.put(temp + "", null);

            }, "writeThread" + i).start();
        }

        for (int i = 0; i < 10; i++) {
            final int temp = i;
            new Thread(() -> {
                m.get(temp + "");

            }, "readThread" + i).start();
        }
    }
}
  咸鱼IT技术交流群:89248062,在这里有一群和你一样有爱、有追求、会生活的朋友! 大家在一起互相支持,共同陪伴,让自己每天都活在丰盛和喜乐中!同时还有庞大的小伙伴团体,在你遇到困扰时给予你及时的帮助,让你从自己的坑洞中快速爬出来,元气满满地重新投入到生活中!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值