zoukankan      html  css  js  c++  java
  • 多线程:锁

    公平和非公平锁

    公平锁:是指多个线程按照申请锁的顺序来获取锁,类似于排队,先来后到,先进先出(FIFO)

    非公平锁:是指多个线程并不按照申请锁的顺序来获取锁,允许加塞。再高并发情况下,有可能载成优先级反转或者饥饿现象。

    juc并发包中的ReentrantLock,可以通过构造函数 的boolean类型来得到公平锁或非公平锁,默认是非公平锁。非公平锁的有点在于吞吐量大于公平锁。

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

    可重入锁

    又名递归锁

    指的是同一线程外层函数获得锁之后,进入内层函数会自动获取锁。即:线程可以进入任何一个它已经拥有的锁所同步着的代码块。

    ReentrantLock/synchronized就是典型的可重入锁。

    可重入锁最大作用就是避免死锁。

    自旋锁

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

    image-20210126095140463

    实现一个简单的自旋锁:

        //原子引用线程
        static AtomicReference<Thread> atomicReference = new AtomicReference<>();
    
        public static void main(String[] args) throws InterruptedException {
            new Thread(()->{
                lock();
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                unLock();
            },"t1").start();
    
            TimeUnit.SECONDS.sleep(1);
            new Thread(()->{
                lock();
                unLock();
            },"t2").start();
        }
    
        public static void lock(){
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+":come in");
            while(!atomicReference.compareAndSet(null, thread)){
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("自旋中");
            }
        }
    
        public static void unLock(){
            Thread thread = Thread.currentThread();
            System.out.println(thread.getName()+":unlock");
            atomicReference.compareAndSet(thread, null);
        }
    

    image-20210126101505610

    独占锁(写锁)/共享锁(读锁)/互斥锁

    独占锁:只该锁一次只能被一个线程所持有,对ReentrantLock/synchronized而言都是独占锁。

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

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

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

    没有加读写锁:

    //资源类
    class MyCache{
    
        private volatile Map<String, Object> map = new HashMap<>();
    
        public void put(String key, Object value){
            System.out.println(Thread.currentThread().getName()+"线程正在写入"+key);
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+"线程写入完成");
        }
    
        public Object get(String key){
            System.out.println(Thread.currentThread().getName()+"线程正在读取"+key);
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName()+"线程读取完成:" + o);
            return o;
        }
    }
    
    public class ReadWriteLockDemo {
        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+"",new Object());
                },i+"").start();
            }
    
            for (int i = 0; i < 5; i++) {
                final int tempInt = i;
                new Thread(()->{
                    myCache.get(tempInt + "");
                },i+"").start();
            }
        }
    }
    

    image-20210126104229049

    写操作:原子+独占,整个过程必须是一个完整的统一体,中间不许被分割,被打断。

    使用读写锁:

    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);
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                map.put(key,value);
                System.out.println(Thread.currentThread().getName()+"线程写入完成");
            }finally {
                rwLock.writeLock().unlock();
            }
    
        }
    
        public Object get(String key){
            rwLock.readLock().lock();
            try {
                System.out.println(Thread.currentThread().getName()+"线程正在读取"+key);
                try {
                    TimeUnit.MILLISECONDS.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Object o = map.get(key);
                System.out.println(Thread.currentThread().getName()+"线程读取完成:" + o);
                return o;
            }finally {
                rwLock.readLock().unlock();
            }
        }
    }
    

    image-20210126105219490

  • 相关阅读:
    Visifire正式版(v1.1)发布
    [转]PSP机能强大!已能模拟运行WINDOWS系统?
    在Silverlight+WCF中应用以角色为基础的安全模式(一)基础篇之角色为基础的安全模式简介 Virus
    C#的加密解密算法,包括Silverlight的MD5算法 Virus
    MMORPG programming in Silverlight Tutorial (10)Implement the sprite’s 2D animation (Part IV)
    Game Script: Rescue Bill Gates
    MMORPG programming in Silverlight Tutorial (9)KeyFrame Animation
    MMORPG programming in Silverlight Tutorial (5)Implement the sprite’s 2D animation (Part II)
    MMORPG programming in Silverlight Tutorial (7)Perfect animation
    MMORPG programming in Silverlight Tutorial (3)Animate the object (Part III)
  • 原文地址:https://www.cnblogs.com/wwjj4811/p/14329144.html
Copyright © 2011-2022 走看看