В механизме блокировки Java, что является справедливой и несправедливой ссылкой, и люди думают, что она относительно сгенерирована, проста, если группа потоков может гарантировать каждый поток, тогда эта блокировка является справедливой блокировкой. Напротив, если вы гарантируете, что каждый поток может получить блокировку, это означает, что поток голодает, тогда эта блокировка является блокировкой без сбоев. Эта статья посвящена ReentrantLock.
Принцип реализации
Итак, как мы можем гарантировать, что каждый поток может получить блокировку?Queue FIFO — идеальное решение, то есть принцип «первым пришел — первым вышел».ReenTrantLock в Java — это справедливая блокировка и нечестная блокировка, реализуемые очередью.
В честных блокировках, если есть другой поток, удерживающий блокировку, или другой поток ожидает этого места в очереди ожидания, то поток для вновь выданного запроса будет помещен в очередь. Вместо справедливой блокировки, только когда блокировка удерживается потоком, новый запрашивающий поток будет помещен в очередь (это то же самое, что и справедливая блокировка). Следовательно, разница между ними в том, что у недобросовестных блокировок больше возможностей для вытеснения блокировок.
Честный замок:
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
#hasQueuedPredecessors的实现
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
Несправедливая блокировка:
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
Пример
Честный замок:
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by Fant.J.
*/
public class MyFairLock {
/**
* true 表示 ReentrantLock 的公平锁
*/
private ReentrantLock lock = new ReentrantLock(true);
public void testFail(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() +"获得了锁");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
MyFairLock fairLock = new MyFairLock();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName()+"启动");
fairLock.testFail();
};
Thread[] threadArray = new Thread[50];
for (int i=0; i<50; i++) {
threadArray[i] = new Thread(runnable);
threadArray[i].start();
}
}
}
Thread-0启动
获得了锁Thread-0获得了锁
Thread-1启动
获得了锁Thread-1获得了锁
Thread-2启动
获得了锁Thread-2获得了锁
Thread-3启动
获得了锁Thread-3获得了锁
Thread-4启动
获得了锁Thread-4获得了锁
Thread-5启动
获得了锁Thread-5获得了锁
Thread-6启动
Thread-7启动
获得了锁Thread-6获得了锁
获得了锁Thread-7获得了锁
Thread-8启动
Thread-9启动
获得了锁Thread-8获得了锁
Thread-10启动
获得了锁Thread-9获得了锁
获得了锁Thread-10获得了锁
Thread-11启动
获得了锁Thread-11获得了锁
Thread-13启动
获得了锁Thread-13获得了锁
Thread-14启动
获得了锁Thread-14获得了锁
Thread-15启动
获得了锁Thread-15获得了锁
Thread-16启动
获得了锁Thread-16获得了锁
Thread-17启动
获得了锁Thread-17获得了锁
Thread-18启动
获得了锁Thread-18获得了锁
Thread-19启动
获得了锁Thread-19获得了锁
Thread-20启动
获得了锁Thread-20获得了锁
Thread-24启动
获得了锁Thread-24获得了锁
Thread-22启动
获得了锁Thread-22获得了锁
Thread-27启动
获得了锁Thread-27获得了锁
Thread-25启动
Thread-26启动
获得了锁Thread-25获得了锁
获得了锁Thread-26获得了锁
Thread-29启动
获得了锁Thread-29获得了锁
Thread-28启动
获得了锁Thread-28获得了锁
Thread-30启动
获得了锁Thread-30获得了锁
Thread-32启动
获得了锁Thread-32获得了锁
Thread-31启动
获得了锁Thread-31获得了锁
Thread-33启动
获得了锁Thread-33获得了锁
Thread-34启动
获得了锁Thread-34获得了锁
Thread-36启动
获得了锁Thread-36获得了锁
Thread-35启动
获得了锁Thread-35获得了锁
Thread-38启动
获得了锁Thread-38获得了锁
Thread-37启动
获得了锁Thread-37获得了锁
Thread-39启动
获得了锁Thread-39获得了锁
Thread-42启动
Thread-41启动
获得了锁Thread-42获得了锁
获得了锁Thread-41获得了锁
Thread-40启动
获得了锁Thread-40获得了锁
Thread-45启动
获得了锁Thread-45获得了锁
Thread-44启动
获得了锁Thread-44获得了锁
Thread-43启动
获得了锁Thread-43获得了锁
Thread-23启动
Thread-46启动
Thread-21启动
获得了锁Thread-23获得了锁
Thread-49启动
Thread-48启动
Thread-12启动
获得了锁Thread-46获得了锁
Thread-47启动
获得了锁Thread-21获得了锁
获得了锁Thread-49获得了锁
获得了锁Thread-48获得了锁
获得了锁Thread-12获得了锁
获得了锁Thread-47获得了锁
Как видите, порядок, в котором потоки получают блокировку, совпадает с порядком, в котором потоки запускаются.
Несправедливая блокировка:
/**
* Created by Fant.J.
*/
public class MyNonfairLock {
/**
* false 表示 ReentrantLock 的非公平锁
*/
private ReentrantLock lock = new ReentrantLock(false);
public void testFail(){
try {
lock.lock();
System.out.println(Thread.currentThread().getName() +"获得了锁");
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
MyNonfairLock nonfairLock = new MyNonfairLock();
Runnable runnable = () -> {
System.out.println(Thread.currentThread().getName()+"启动");
nonfairLock.testFail();
};
Thread[] threadArray = new Thread[10];
for (int i=0; i<10; i++) {
threadArray[i] = new Thread(runnable);
threadArray[i].start();
}
}
}
Thread-1启动
Thread-0启动
Thread-0获得了锁
Thread-1获得了锁
Thread-8启动
Thread-8获得了锁
Thread-3启动
Thread-3获得了锁
Thread-4启动
Thread-4获得了锁
Thread-5启动
Thread-2启动
Thread-9启动
Thread-5获得了锁
Thread-2获得了锁
Thread-9获得了锁
Thread-6启动
Thread-7启动
Thread-6获得了锁
Thread-7获得了锁
Видно, что получение блокировок недобросовестными блокировками происходит не по порядку, то есть происходит процесс вытеснения блокировок.
Наконец
Для каких случаев подходят несправедливые блокировки и честные блокировки, и каковы их преимущества и недостатки?
Преимущества и недостатки:
Неблокирующая производительность, чем справедливая справедливая производительность. Во-первых, восстановить подвесную нить, существует серьезная задержка между нитью и действительно запущена. Кроме того, замок может быть более полно несправедливым использование нарезки времени процессора, как можно больше, чтобы уменьшить время простоя заданного процессора.
сцены, которые будут использоваться
Что же касается сценария использования, то он фактически связан с их атрибутами поочередно, например, если время занятия (обработки) потока в бизнесе намного больше, чем время ожидания потока, то эффективность использования недобросовестных блокировок не очевидна, но использование честных замков дает большой контроль над бизнесом.