zoukankan      html  css  js  c++  java
  • ReentrantLock(重入锁)的公平性

    在ReentrantLock中,对于公平和非公平的定义是通过对同步器AbstractQueuedSynchronizer的扩展加以实现的

    非公平的获取语义:

    image

    公平的获取语义:

    image

    比较非公平的获取,仅加入了当前线程(Node)之前是否有前置节点在等待的判断

    编写一个测试来观察公平和非公平锁在获取锁时的区别,在测试用例中定义了内部
    类ReentrantLock2,该类主要公开了getQueuedThreads()方法,该方法返回正在等待获取锁的线
    程列表,由于列表是逆序输出,为了方便观察结果,将其进行反转

    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class FairAndUnfairTest {
    
        private static Lock fairLock = new ReentrantLock2(true);
        private static Lock unfairLock = new ReentrantLock2(false);
    
        public static void main(String[] args) throws Exception {
    //        fair();
            unfair();
        }
        public static void fair() {
    
            System.out.println("fair version");
            for (int i = 0; i < 5; i++) {
                Thread thread = new Thread(new Job(fairLock)) {
                    public String toString() {
                        return getName();
                    }
                };
                thread.setName("" + i);
                thread.start();
            }
            // sleep 5000ms
        }
    
    
        public static void unfair() {
            System.out.println("unfair version");
            for (int i = 0; i < 5; i++) {
                Thread thread = new Thread(new Job(unfairLock)) {
                    public String toString() {
                        return getName();
                    }
                };
                thread.setName("" + i);
                thread.start();
            }
            // sleep 5000ms
        }
    
    
        private static class Job implements Runnable {
    
            private Lock lock;
            public Job(Lock lock) {
                this.lock = lock;
            }
            @Override
            public void run() {
                for (int i = 0; i < 2; i++) {
                    lock.lock();
                    try {
                        TimeUnit.SECONDS.sleep(2);
                        System.out.println("Lock by:"
                                + Thread.currentThread().getName() + " and "
                                + ((ReentrantLock2) lock).getQueuedThreads()
                                + " waits.");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }
    
    
        private static class ReentrantLock2 extends ReentrantLock {
            public ReentrantLock2(boolean fair) {
                super(fair);
            }
            private static final long serialVersionUID = 1773716895097002072L;
            public Collection<Thread> getQueuedThreads() {
                List<Thread> threads = new ArrayList<Thread>(super.getQueuedThreads());
                Collections.reverse(threads);
                return threads;
            }
        }
    }

    调用非公平方法,返回结果:

    unfair version
    Lock by:0 and [1, 2, 3, 4] waits.
    Lock by:0 and [1, 2, 3, 4] waits.
    Lock by:1 and [2, 3, 4] waits.
    Lock by:1 and [2, 3, 4] waits.
    Lock by:2 and [3, 4] waits.
    Lock by:2 and [3, 4] waits.
    Lock by:3 and [4] waits.
    Lock by:3 and [4] waits.
    Lock by:4 and [] waits.
    Lock by:4 and [] waits.

    调用公平方法,返回结果:

    fair version
    Lock by:0 and [1, 2, 4, 3] waits.
    Lock by:1 and [2, 4, 3, 0] waits.
    Lock by:2 and [4, 3, 0, 1] waits.
    Lock by:4 and [3, 0, 1, 2] waits.
    Lock by:3 and [0, 1, 2, 4] waits.
    Lock by:0 and [1, 2, 4, 3] waits.
    Lock by:1 and [2, 4, 3] waits.
    Lock by:2 and [4, 3] waits.
    Lock by:4 and [3] waits.
    Lock by:3 and [] waits.

    可以明显看出,在非公平获取的过程中,“插队”现象非常严重,后续获取锁的线程根本不顾及sync队列中等待的线程,而是能获取就获取。反观公平获取的过程,锁的获取就类似线性化的

  • 相关阅读:
    VS Code 的常用快捷键
    oj教程--坑
    oj教程--学习顺序
    oj教程--链表
    oj教程--队列
    oj教程--栈
    【MySQL】汇总数据
    【MySQL】使用WHERE子句
    【MySQL】SELECT语句
    【MySQL】使用MySQL(连接、选择数据库、显示数据库和表信息)
  • 原文地址:https://www.cnblogs.com/xiongmaotailang/p/6139214.html
Copyright © 2011-2022 走看看