重入锁之公平性

版权声明: https://blog.csdn.net/Dongguabai/article/details/84191747

公平是针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序。

这样就需要内部维护一个FIFO队列,Object有个wait()和notify()方法(具体可参看https://blog.csdn.net/Dongguabai/article/details/82230279),但是notify()是随机释放一个,那么我们如何保证释放的是队列中的第一个呢。那就对不同对象进行wait()和notify(),相当于notify()第一个对象,肯定就可以唤醒第一个对象等待队列中的wait()的线程,这样就实现了公平性。

package com.example.demoClient;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Dongguabai
 * @date 2018/11/10 16:53
 */
public class FairLock {

	private boolean isLocked = false;
	private Thread lockingThread = null;
	//封装对象到有序集合队列
	private List<QueueObject> waitingThreads = new ArrayList<QueueObject>();

	public void lock() throws InterruptedException {
		//每次lock()都会创建一个相应的对象
		QueueObject queueObject = new QueueObject();
		//由于wait(),需要同步置等待队列中
		synchronized (this) {
			waitingThreads.add(queueObject);
		}

		try {
			//调用对象的doWait()方法
			queueObject.doWait();
		} catch (InterruptedException e) {
			synchronized (this) {
				waitingThreads.remove(queueObject);
			}
			throw e;
		}
	}

	//同步,由于notify()
	public synchronized void unlock() {
		if (this.lockingThread != Thread.currentThread()) {
			throw new IllegalMonitorStateException("Calling thread has not locked this lock");
		}
		isLocked = false;
		lockingThread = null;
		if (waitingThreads.size() > 0) {
			waitingThreads.get(0).doNotify();
		}
	}
}
package com.example.demoClient;

/**
 * @author Dongguabai
 * @date 2018/11/10 16:53
 */
public class QueueObject {

	//是否唤醒
	private boolean isNotified = false;

	public synchronized void doWait() throws InterruptedException {

		//如果不是唤醒,继续wait()
		while (!isNotified) {
			this.wait();
		}

		this.isNotified = false;

	}

	//notify
	public synchronized void doNotify() {
		this.isNotified = true;
		this.notify();
	}

	public boolean equals(Object o) {
		return this == o;
	}

}

接下来简单看看ReentrantLock是如何实现公平锁的。

查看公平的AQS实现:

主要是依靠与这个方法:

比较公平和非公平AQS实现的acquire()方法:

发现其实方法基本一致,但是公平锁有一个特殊的hasQueuedPredecessors()方法。大致从名称来看就是判断队列是否存在前驱节点。

有前驱结点就说明有现成应该比当前线程应该更早的获取锁,有前置就返回true。也就是说当前线程此时不应该获取锁。

===============================================================================================

以下内容转自:http://ifeve.com/starvation-and-fairness/

可重入公平锁代码:

package com.example.demoClient;

import java.util.ArrayList;
import java.util.List;

public class FairLock {

    private boolean isLocked = false;

    private Thread lockingThread = null;

    private List<QueueObject> waitingThreads =

            new ArrayList<QueueObject>();


    public void lock() throws InterruptedException {

        QueueObject queueObject = new QueueObject();

        boolean isLockedForThisThread = true;

        synchronized (this) {

            waitingThreads.add(queueObject);

        }


        while (isLockedForThisThread) {

            synchronized (this) {

                isLockedForThisThread =

                        isLocked || waitingThreads.get(0) != queueObject;

                if (!isLockedForThisThread) {

                    isLocked = true;

                    waitingThreads.remove(queueObject);

                    lockingThread = Thread.currentThread();

                    return;

                }

            }

            try {

                queueObject.doWait();

            } catch (InterruptedException e) {

                synchronized (this) {
                    waitingThreads.remove(queueObject);
                }

                throw e;

            }

        }

    }


    public synchronized void unlock() {

        if (this.lockingThread != Thread.currentThread()) {

            throw new IllegalMonitorStateException(

                    "Calling thread has not locked this lock");

        }

        isLocked = false;

        lockingThread = null;

        if (waitingThreads.size() > 0) {

            waitingThreads.get(0).doNotify();

        }

    }

}
package com.example.demoClient;

public class QueueObject {

    private boolean isNotified = false;

    public synchronized void doWait() throws InterruptedException {
        while (!isNotified) {
            this.wait();
        }
        this.isNotified = false;
    }

    public synchronized void doNotify() {
        this.isNotified = true;
        this.notify();
    }

    @Override
    public boolean equals(Object o) {

        return this == o;

    }
}

猜你喜欢

转载自blog.csdn.net/Dongguabai/article/details/84191747