In The Java locking mechanism, what is the reference between fair and unfair? Personally, it depends on the result produced. Simply speaking, if a thread group can guarantee that every thread can get the lock, then the lock is fair. On the other hand, if no thread is guaranteed to acquire the lock, that is, some thread is starving, then the lock is unfair. This article focuses on ReenTrantLock.
Realize the principle of
So how do you ensure that every thread gets a lock? Queue FIFO is a perfect solution, first-in, first-out. Java’s ReenTrantLock is a queue implementation of fair and unfair locks.
In a fair lock, if another thread holds the lock or another thread is waiting on the queue, the thread that makes the new request will be placed on the queue. Instead of a fair lock, a new thread will be queued only if the lock is held by a thread (which is the same as a fair lock). So, the difference is that unfair locks have more opportunities to preempt locks.
Fair lock:
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if(! hasQueuedPredecessors() && compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);
return true; }}# hasQueuedPredecessors implementation
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
returnh ! = t && ((s = h.next) == null || s.thread ! = Thread.currentThread()); }Copy the code
Unfair lock:
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true; }}Copy the code
The sample
Fair lock:
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Fant.J.
*/
public class MyFairLock {
/**
* truePrivate ReentrantLock lock = new ReentrantLock(true);
public void testFail(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() +"Got the lock.");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
MyFairLock fairLock = new MyFairLock();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName()+"Start");
fairLock.testFail();
};
Thread[] threadArray = new Thread[50];
for(int i=0; i<50; i++) { threadArray[i] = new Thread(runnable); threadArray[i].start(); }}}Copy the code
Thread0 is enabled to acquire the lock thread-1 is enabled to acquire the lock thread-1 is enabled to acquire the lock thread-2 is enabled to acquire the lock thread-3 is enabled to acquire the lock Thread4 acquired the lock; thread5 acquired the lock; Thread6 acquired the lock; thread7 acquired the lock Thread-8 started thread-9 started and acquired the lock Thread-10 started and acquired the lock thread-9 acquired the lock thread-10 acquired the lock thread-11 acquired the lock Thread13 obtained the lock; thread14 obtained the lock; Thread15 obtained the lock; Thread16 obtained the lock Thread17 got the lock thread17 got the lock thread18 got the lock thread19 got the lock thread20 got the lock Thread24 obtained the lock; thread22 obtained the lock; Thread27 obtained the lock; Thread25 started; Thread26 started The lock was acquired; Thread25 acquired the lock; Thread26 acquired the lock; Thread29 acquired the lock; thread28 acquired the lock; thread30 was enabled The lock was acquired; the lock was acquired; thread30 was acquired; thread32 was enabled; the lock was acquired; thread31 was enabled; thread33 was enabled; thread34 was enabled The lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired The lock was acquired; the lock was acquired; The lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired The lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired; the lock was acquired Thread-46 Started Thread-21 Started Thread-23 Obtained the lock thread-49 started thread-48 started thread-12 Obtained the lock thread-46 obtained the lock thread-47 started Thread21 acquired the lock Thread49 acquired the lock Thread48 acquired the lock Thread12 acquired the lock Thread47 acquired the lockCopy the code
As you can see, the order in which the locks are acquired is the order in which the threads are started.
Unfair lock:
/**
* Created by Fant.J.
*/
public class MyNonfairLock {
/**
* falsePrivate ReentrantLock lock = new ReentrantLock(false);
public void testFail(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() +"Got the lock.");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
MyNonfairLock nonfairLock = new MyNonfairLock();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName()+"Start");
nonfairLock.testFail();
};
Thread[] threadArray = new Thread[10];
for(int i=0; i<10; i++) { threadArray[i] = new Thread(runnable); threadArray[i].start(); }}}Copy the code
Thread-1 enabled thread-0 enabled thread-0 obtained the lock thread-1 obtained the lock thread-8 enabled thread-8 obtained the lock thread-3 enabled thread-3 obtained the lock thread-4 enabled thread-4 obtained the lock Thread-5 Enabled thread-2 enabled thread-9 Enabled Thread-5 obtained the lock thread-2 obtained the lock thread-9 obtained the lock thread-6 enabled thread-7 obtained the lock thread-7 obtained the lockCopy the code
It can be seen that the acquisition of an unfair lock is out of order, that is, there is a process of preempting the lock.
The last
That is not fair lock and fair lock for what occasions to use it, what are their advantages and disadvantages?
The advantages and disadvantages:
Unfair lock performance is higher than fair lock performance. First, there is a significant delay between resuming a suspended thread and actually running it. Moreover, the unfair lock can make full use of the CPU time slice and reduce the idle state time of the CPU as far as possible.
Usage scenarios
Usage scenarios are dependent on their attributes. For example, if a business has threads that take much longer to process than threads that wait, using unfair locks is not efficient, but using fair locks gives the business much more control.