美文网首页
公平锁和非公平锁&可重入锁&自旋锁&独占锁/共享锁

公平锁和非公平锁&可重入锁&自旋锁&独占锁/共享锁

作者: 霓裳梦竹 | 来源:发表于2019-12-30 17:30 被阅读0次

    文章同步更新在个人公众号“梓莘”,欢迎大家关注,相互交流。

    公平锁和非公平锁

    公平锁:是指多个线程按照申请锁的顺序来获取锁,也就是遵循先来后到

    非公平锁:是指多个线程获取锁的顺序并不是安装申请锁的顺序,有可能后申请锁的线程优先获得锁,在高并发环境下,有可能造成优先级反转或者饥饿现象。非公平就是允许加塞

    在并发包ReentrantLock的创建可以执行构造函数的boolean类型来得到公平锁和非公平锁,默认是非公平锁。

    区别:

    公平锁:Threads acquire a fair lock in the order in which they required it

    公平锁,就是很公平,在并发环境下,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会安装FIFO的规则从队列充取到自己。

    非公平锁:a nonfair lock permits barging:threads requesting a lock can jump ahead of the qyeye of waiting threads if the lock happend to be available when it is requested.

    非公平锁比较野蛮,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式

    对于Java ReentrantLock而言:

    通过构造函数指定该锁是否是公平锁,默认是非公平锁,非公平锁的优点在于吞吐量比公平锁大。

    对于synchronized而言,也是一种非公平锁。

       /**
         * Creates an instance of {@code ReentrantLock}.
         * This is equivalent to using {@code ReentrantLock(false)}.
         */
      public ReentrantLock() {
            sync = new NonfairSync();
        }
    
    
    /**
         * Creates an instance of {@code ReentrantLock} with the
         * given fairness policy.
         *
         * @param fair {@code true} if this lock should use a fair ordering policy
         */
     public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }
    
    

    可重入锁

    指的是同一线程外层函数获得锁之后,内层递归函数仍然能获得该锁的代码,在同一个线程在外层方法获得锁的时候,在进入内层方法会自动获取锁。也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块。

    package com.zixin;
    
    class Photo{
        public synchronized void sendSms() throws Exception{
            System.out.println(Thread.currentThread().getId()+"  invoked sendSMS");
            sendEmail();
        }
    
        public synchronized void sendEmail() throws Exception{
            System.out.println(Thread.currentThread().getId()+"  invoked sendEmail");
    
        }
    }
    /**
     * @ClassName ReenterLockDemo
     * @Description 指的是同一线程外层函数获得锁之后,内层递归函数仍然能获得该锁的代码,在同一个线程在外层方法获得锁的时候,在进入内层方法会自动获取锁。也就是锁,线程可以进入任何一个它已经拥有的锁所同步着的代码块。
     * @Author zishen
     * @Date 2019/12/30 9:36
     * @Version 1.0
     **/
    public class ReenterLockDemo {
    
        /**
         * 11  invoked sendSMS
         * 11  invoked sendEmail
         * 10  invoked sendSMS
         * 10  invoked sendEmail
         * @param args
         */
        public static void main(String[] args) {
            Photo p = new Photo();
            new Thread(()->{
                try {
                    p.sendSms();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"t1").start();
            new Thread(()->{
                try {
                    p.sendSms();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            },"t2").start();
        }
    
    }
    
    

    自旋锁

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

    package com.zixin;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * @ClassName SpinLockDemo
     * @Description 手写一个自旋锁
     * @Author zixin
     * @Date 2019/12/30 10:34
     * @Version 1.0
     **/
    public class SpinLockDemo {
        //原子引用线程
        AtomicReference<Thread> atomicReference = new AtomicReference<Thread>();
        public void myLock(){
            Thread thread = Thread.currentThread();
            System.out.println(Thread.currentThread().getName()+" come in");
            while(!atomicReference.compareAndSet(null,thread)){
    
            }
        }
        public void myUnLock(){
            Thread thread =Thread.currentThread();
            atomicReference.compareAndSet(thread,null);
            System.out.println(Thread.currentThread().getName()+" invoked myUnLock");
        }
    
        /**
         * AA come in
         * BB come in
         * AA invoked myUnLock
         * BB invoked myUnLock
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
    
            SpinLockDemo spinLockDemo = new SpinLockDemo();
            new Thread(()->{
                spinLockDemo.myLock();
                try {
                    TimeUnit.SECONDS.sleep(5);
                    spinLockDemo.myUnLock();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"AA").start();
            TimeUnit.SECONDS.sleep(1);
            new Thread(()->{
                spinLockDemo.myLock();
                spinLockDemo.myUnLock();
            },"BB").start();
        }
    }
    
    

    独占锁/共享锁

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

    共享锁:指该锁可被多个线程多持有。

    对ReentrantReadWriteLock其读锁是共享锁,其写锁是独占锁。

    读锁的共享锁可保证并发读是非常高效的,读写,写读,写写的过程是互斥的。

    package com.zixin;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    class MyCache{
        private volatile Map<String,Object> map = new HashMap<>();
    
        private ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
        public void put(String key,Object value){
            rwlock.writeLock().lock();
    
            try {
                System.out.println(Thread.currentThread().getName()+" 正在写入:"+key);
                TimeUnit.MILLISECONDS.sleep(500);
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+" 写入完成:"+key);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                rwlock.writeLock().unlock();
            }
    
        }
        public void get(String key){
            rwlock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName()+" 正在读取:"+key);
                TimeUnit.MILLISECONDS.sleep(500);
                Object result = map.get(key);
                System.out.println(Thread.currentThread().getName()+" 读取完成:"+result);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                rwlock.readLock().unlock();
            }
    
        }
        public void clearMap(){
            map.clear();
        }
    }
    /**
     * @ClassName ReadWriteLockDemo
     * @Description 读写锁
     * @Author zixin
     * @Date 2019/12/30 11:38
     * @Version 1.0
     **/
    public class ReadWriteLockDemo {
    
        /**
         * 0 正在写入:0
         * 0 写入完成:0
         * 1 正在写入:1
         * 1 写入完成:1
         * 2 正在写入:2
         * 2 写入完成:2
         * 3 正在写入:3
         * 3 写入完成:3
         * 4 正在写入:4
         * 4 写入完成:4
         * 0 正在读取:0
         * 1 正在读取:1
         * 2 正在读取:2
         * 3 正在读取:3
         * 4 正在读取:4
         * 1 读取完成:1
         * 2 读取完成:2
         * 0 读取完成:0
         * 3 读取完成:3
         * 4 读取完成:4
         * @param args
         */
        public static void main(String[] args) {
            MyCache myCache = new MyCache();
    
            for (int i = 0; i <5 ; i++) {
                final int tempInt = i;
                new Thread(()->{
                    myCache.put(tempInt+"",tempInt+"");
                },String.valueOf(i)).start();
            }
    
            for (int i = 0; i <5 ; i++) {
                final int tempInt = i;
                new Thread(()->{
                    myCache.get(tempInt+"");
                },String.valueOf(i)).start();
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:公平锁和非公平锁&可重入锁&自旋锁&独占锁/共享锁

          本文链接:https://www.haomeiwen.com/subject/gkvmoctx.html