Sprechen Sie über Sperre

Machen Sie es sich zur Gewohnheit, gemeinsam zu schreiben! Dies ist der erste Tag meiner Teilnahme an der „Nuggets Daily New Plan·April Update Challenge“,Klicken Sie hier, um die Ereignisdetails anzuzeigen

1. Einleitung

lock ist eine Schnittstelle und hat viele Implementierungen.Die gebräuchlichsten sind wiedereintrittsfähige Sperren (ReentrantLock) und Lese-Schreib-Sperren(Read, WriteLock), die sich in einem Unterpaket von locks unter JUC befinden. Lock muss Sperren explizit erwerben und freigeben.Obwohl es nicht so praktisch ist wie das implizite Erwerben von Sperren, hat esSynchronisationsfunktionen wie die Funktionsfähigkeit des Erwerbs und der Freigabevon Sperren, das unterbrechbare Erwerben von Sperren und das Erwerben von Sperrenmit Zeitüberschreitung.

Bild-20220411135241875

1.1- Einführung in die Methode

  • void lock(): erwirbt die Sperre, wenn die Sperre nicht verfügbar ist, wird der aktuelle Thread blockiert, bis die Sperre erworben wird;

    Dies stellt die einfachste und gebräuchlichste Methode zum Erwerb einer Sperre dar. Sie hebt die Sperre nicht automatisch auf, wenn eine Ausnahme auftritt, wie bei „synchro- nised“, also muss sie im finally-Block freigegeben werden, um sicherzustellen, dass die Sperre normal aufgehoben werden kann, wenn eine Exception auftritt. Es sollte beachtet werden, dass diese Methode nicht unterbrochen werden kann, also wenn sie sich in einer Deadlock-Situation befindet, wird lock() ewig warten.

  • void lockInterruptably() löst InterruptedException aus: Erwirbt eine unterbrechbare Sperre und kehrt zurück, wenn sie unterbrochen oder die Sperre erworben wird Wenn die Sperre nicht verfügbar ist, wird der aktuelle Thread blockiert, bis die Sperre erworben oder unterbrochen wird;

    Im Gegensatz zu lock() unterstützt lockInterruptably() die Unterbrechung während des Wartens auf die Sperre, oder man kann sagen, dass lockInterruptibly mit einer höheren Priorität auf die Thread.interrupt-Methode antwortet Das Abrufen der Sperre löst stattdessen eine InterruptedException aus. Und lock() hat die Priorität, die Sperre zu erwerben, bevor auf den Interrupt reagiert wird. Es ist sinnlos, Interrupt auszuführen, während die Sperre wartet. Es muss warten, bis die Sperre die Sperre erlangt, bevor sie auf den Interrupt antwortet.

  • boolean tryLock(): versuchen, die Sperre zu erwerben und sofort zurückzukehren, true: die Sperre erfolgreich erwerben, false: die Sperre erwerben, fehlgeschlagen;

  • boolean tryLock(long time, TimeUnit unit) throws InterruptedException:尝试在指定的超时时间获取锁,当获取到锁时返回true;当超时或被中断时返回false;

  • Condition newCondition():返回一个和锁绑定的条件队列;在等待条件之前线程必须先获取当前锁,同时await()方法会原子地释放锁,并在返回之前重新获取到锁;

  • void unlock():释放锁;

ReentrantLock和ReadWriteLock是此接口的实现:

Bild-20220411140005843

2.Lock锁的意义

  1. 对比于更加古老的synchronized锁,lock锁的操作更加的灵活,Lock提供了更丰富的锁操作
  2. 通常来说锁的作用是提供多线程对共享资源的独占访问,一次只能由一个线程获得锁,只有获得锁的线程拥有对共享资源的访问权限,但是有些所可以做到对共享资源的并发访问,比如读写锁可以并发的读共享资源。

3.用法

下面的代码是一个基本的示例,声明一个Lock锁的实例对象,调用lock方法加锁,与synchronized自动解锁所不同的是Lock需要手动释放锁,正是如此是的lock锁有了很强大的灵活性。

Lock lock = new ReentrantLock();
lock.lock();
try{
  
}finally {
  lock.unlock();
}
复制代码

3.1-Condition 的用法

关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock 锁的 newContition()方法返回的 Condition 对象也可以实现等待/通知模式。 用 notify()通知时,JVM 会随机唤醒某个等待的线程, 而使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:

  • await() : Der aktuelle Thread wartet und gleichzeitig wird die Sperre freigegeben. Wenn andere Threads signal()die Methode aufrufen, erhält der schlafende Thread die Sperre zurück und fährt mit der Ausführung des Codes fort (wacht dort auf, wo er schläft).
  • signal() : Wird verwendet, um einen wartenden Thread aufzuwecken.

Es ist zu beachten, dass der Thread vor dem Aufruf der await()/signal()-Methode von Condition auch die entsprechende Lock-Sperre halten muss.Nach dem Aufruf von await() gibt der Thread die Sperre frei.In der Warteschlange des Objekts , wird ein Thread aufgeweckt, und der aufgeweckte Thread beginnt zu versuchen, die Sperre zu erwerben, und fährt mit der Ausführung fort, sobald die Sperre erfolgreich erworben wurde.

class Share {
//通过两个线程对number进行加减操作,一个线程当number == 0时 对number++,另外一个线程当number == 1时对number--
    private Integer number = 0;
​
    private ReentrantLock lock = new ReentrantLock();
​
    private Condition newCondition = lock.newCondition();
​
    // number++
    public void incr() {
        try {
            lock.lock(); // 加锁
            while (number != 0) {
                newCondition.await();//沉睡
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            newCondition.signal(); //唤醒另一个沉睡的线程 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
​
    // number--
    public void decr() {
        try {
            lock.lock();
            while (number != 1) {
                newCondition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + "::" + number);
            newCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
​
public class LockDemo2 {
    public static void main(String[] args) {
        Share share = new Share();
​
        new Thread(()->{
            for (int i=0;i<=10;i++){
                share.incr();
            }
        },"AA").start();
​
        new Thread(()->{
            for (int i=0;i<=10;i++){
                share.decr();
            }
        },"BB").start();
        /**out:
         * AA::1
         * BB::0
         * AA::1
         * BB::0
         * .....
         */     
    }
}
复制代码

Ich denke du magst

Origin juejin.im/post/7085252554665230350
Empfohlen
Rangfolge