让我“锁”住你的心

公平锁与非公平锁

在这里插入图片描述

可重入锁(递归锁)

在这里插入图片描述
意思就是当有某一个线程拿到了外层函数的锁之后,它就自动拿到了内层函数的锁。

还有些晦涩难懂?咱们来举个栗子🌰

class phone{
    public synchronized  void get(){
        System.out.println(Thread.currentThread().getId()+"get方法");
        set();
    }
    public  synchronized void set(){
        System.out.println(Thread.currentThread().getId()+"注意我是set方法");
    }
}

public class ReentrantlockDemo {
    public static void main(String[] args) throws InterruptedException {
        phone phone= new phone();
        iphone iphone=new iphone();
        new Thread(()->{
            phone.get();
        }, "t1").start();
        new Thread(()->{
            phone.get();
        }, "t2").start();
        TimeUnit.SECONDS.sleep(2);

        System.out.println("==========以上是synchronized是递归锁(可重入锁)的验证==========");

    }
}

set方法在get方法之内,并且两个方法都加了锁,当线程1,或者线程2拿到了get方法的锁,那么自然也就拿了set方法的锁。看结果`

12get方法
12注意我是set方法
13get方法
13注意我是set方法
==========以上是synchronized是递归锁(可重入锁)的验证==========

接下来验证Reentrantlock也是递归锁。如下

class iphone implements  Runnable{
    Lock lock =new ReentrantLock();

    @Override
    public void run() {
        get();
    }

    public void get() {
        lock.lock();
        try {
        System.out.println(Thread.currentThread().getId()+"get方法");
        set();
        }finally {
            lock.unlock();
        }
    }
    public  void set(){
        lock.lock();
        try {
        System.out.println(Thread.currentThread().getId()+"注意我是set方法");
        }finally {
            lock.unlock();
        }

    }
}





public class ReentrantlockDemo {
    public static void main(String[] args) throws InterruptedException {
    	 System.out.println("==========以下是Reentrantlock是递归锁(可重入锁)的验证==========");

        Thread thread1 =new Thread(iphone);
        Thread thread2= new Thread(iphone);

        thread1.start();
        thread2.start();

    }
}

结果:

==========以下是Reentrantlock是递归锁(可重入锁)的验证==========
15get方法
15注意我是set方法
16get方法
16注意我是set方法

自旋锁

首先,自旋是不是很眼熟,当我们在说CAS的时候是不是也谈到了它的自旋,就是因为它的do,while。同样的道理,自旋锁就是线程如果尝试获取锁失败后,不会立即阻塞,而是会采用循环访问的方式获取锁,这样的好处是减少了上下文的切换,缺点是增加了CPU的消耗,真是“成也萧何,败也萧何”。
还是来举个栗子🌰。


import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

public class SpinLockDemo {
        static  int num =0;
    AtomicReference<Thread> atomicReference =new AtomicReference();
    public  void lock(){
        Thread thread= Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"come on");
        
        while (!atomicReference.compareAndSet(null, thread)){
            if (num <= 2) {
                num++;
                System.out.println(Thread.currentThread().getName()+" 我来看看你这个占着茅坑不拉粑粑的家伙");
            }
        }
    }
    public void unlock(){
        Thread thread = Thread.currentThread();
        atomicReference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName()+"走了");
    }

    public static void main(String[] args) {
        SpinLockDemo spinLockDemo =new SpinLockDemo();
        new Thread(()->{
                spinLockDemo.lock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            spinLockDemo.unlock();
        }, "t1").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(()->{
            spinLockDemo.lock();
            spinLockDemo.unlock();
        }, "t2").start();

    }
}

结果:

t1come on
t2come on
t2 我来看看你这个占着茅坑不拉粑粑的家伙
t2 我来看看你这个占着茅坑不拉粑粑的家伙
t2 我来看看你这个占着茅坑不拉粑粑的家伙
t1走了
t2走了

t1先来,看见原子引用是空,然后将原子引用由空变成自己,然后阻塞,当t2线程来的时候先看原子引用里是空吗,不是空,则陷入这个循环,也就是自旋,当然这里不仅仅是自旋三次,我只是为了方便演示三次之后就没有再打印,只有当t1线程醒了的时候,执行了lock.unlock将原子引用由它自己,变为空,才能使的线程二while中的判断为false。线程2才能继续进行。

读写锁

首先来谈谈为什么需要读写锁,读写锁是为何而生的。
它的产生我觉得在于写的特殊性,写不能与读共存,意思就是,当某个线程要开始写时,他必须将他想写的的东西都写完,不然总不能把孩子憋坏吧。还有写更不能与写共存。也就是说,一个线程写的时候别的线程是不能抢占CPU来写,不然的话写的东西岂不是就乱套了。还有就是读和读是可以共存的。我们一起看一眼总不会怎么样吧。
因为这些,如果我们用Reentrantlock,或者synchronized就一下打死了一大片,就像如果我们把只是把它的写方法给锁住之后,还是会有别的线程能调用到他的读方法。如果都锁住,则不能同时读。这就是为何会出现了读写锁。
在这里插入图片描述
还是举个栗子🌰:


import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class cache{
    private    volatile HashMap<String,Object> map =new HashMap();
    private ReentrantReadWriteLock readWriteLock =new ReentrantReadWriteLock();

    public  void put(String key,Object value){
        readWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"开始写"+key);
            try {
                TimeUnit.MICROSECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key, value);
            System.out.println(Thread.currentThread().getName()+"写完了");

        }catch (Exception e){
            e.printStackTrace();
        }finally {

            readWriteLock.writeLock().unlock();
        }

    }

    public  void get(String key){
        readWriteLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+"开始读");
            try {
                TimeUnit.MICROSECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object result =  map.get(key);
            System.out.println(Thread.currentThread().getName()+"读结束"+result);

        }catch (Exception e){
            e.printStackTrace();
        }finally {

            readWriteLock.readLock().unlock();
        }

    }
}




public class RAWLockDemo {
    public static void main(String[] args) {
        cache cache =new cache();
        for (int i =0;i<5;i++) {
            final  int temp = i;
            new Thread(() -> {
                cache.put(temp+"", temp+"");
            }, String.valueOf(i)).start();
        }



        for (int i =0;i<5;i++) {
            final  int temp = i;
            new Thread(() -> {
                cache.get(temp+"");
            }, String.valueOf(i)).start();
        }
    }

结果:作为有读写锁,右为无读写锁
在这里插入图片描述在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值