Heim > Java > javaLernprogramm > Hauptteil

Was sind die häufigsten Fallstricke von ReentrantLock in Java?

王林
Freigeben: 2023-05-10 18:55:14
nach vorne
1558 Leute haben es durchsucht

Lock-Einführung

Lock ist eine Schnittstelle der obersten Ebene und alle ihre Methoden sind wie folgt:

Was sind die häufigsten Fallstricke von ReentrantLock in Java?

Die Unterklassenliste lautet wie folgt:

Was sind die häufigsten Fallstricke von ReentrantLock in Java?

Normalerweise verwenden wir ReentrantLock, um sie zu definieren Instanzen, Die Beziehung zwischen ihnen ist in der folgenden Abbildung dargestellt:

Was sind die häufigsten Fallstricke von ReentrantLock in Java?

PS: Sync bedeutet Synchronisationssperre, FairSync bedeutet faire Sperre und NonfairSync bedeutet unfaire Sperre.

ReentrantLock-Verwendung

Das Erlernen einer Fertigkeit beginnt mit deren Verwendung, daher sind wir keine Ausnahme. Schauen wir uns zunächst die grundlegende Verwendung von ReentrantLock an:

public class LockExample {
    // 创建锁对象
    private final ReentrantLock lock = new ReentrantLock();
    public void method() {
        // 加锁操作
        lock.lock();
        try {
            // 业务代码......
        } finally {
            // 释放锁
            lock.unlock();
        }
    }
}
Nach dem Login kopieren

Nach dem Erstellen von ReentrantLock gibt es zwei wichtige Punkte:

  • Sperrvorgang: lock()

  • Sperrvorgang freigeben: unlock()

Fallstricke in ReentrantLock

1. ReentrantLock ist standardmäßig eine unfaire Sperre

Viele Leute werden denken (besonders für unerfahrene Freunde), Die Standardimplementierung von ReentrantLock ist eine faire Sperre, dies ist jedoch standardmäßig nicht der Fall (dies liegt hauptsächlich an Leistungsaspekten). Die Ausführungsergebnisse des oben genannten Programms lauten wie folgt:

Anhand der obigen Ausführungsergebnisse können wir erkennen, dass ReentrantLock standardmäßig eine unfaire Sperre ist. Da die Namen der Threads entsprechend der Reihenfolge ihrer Erstellung erhöht werden, sollte die Ausführung der Threads in der Reihenfolge erhöht werden, wenn es sich um eine faire Sperre handelt Threads sind außer Betrieb. Diese Beschreibung ReentrantLock ist standardmäßig eine unfaire Sperre. Es ist auch sehr einfach, ReentrantLock als faire Sperre festzulegen. Sie müssen beim Erstellen von ReentrantLock nur einen echten Konstruktionsparameter festlegen:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 创建锁对象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 定义线程任务
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 加锁
                lock.lock();
                try {
                    // 打印执行线程的名字
                    System.out.println("线程:" + Thread.currentThread().getName());
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            }
        };
        // 创建多个线程
        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}
Nach dem Login kopieren
Was sind die häufigsten Fallstricke von ReentrantLock in Java?

Die Ausführungsergebnisse des obigen Programms sind wie folgt folgt:

Wie aus den obigen Ergebnissen ersichtlich ist, wird ReentrantLock zu einer fairen Sperre, wenn wir den wahren Konstruktionsparameter für ReentrantLock explizit festlegen, und die Reihenfolge, in der Threads Sperren erwerben, wird ordnungsgemäß.

Tatsächlich können wir anhand des Quellcodes von ReentrantLock auch erkennen, ob es sich um eine faire Sperre oder eine unfaire Sperre handelt. Ein Teil des Quellcodes von ReentrantLock ist wie folgt implementiert:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 创建锁对象(公平锁)
    private static final ReentrantLock lock = new ReentrantLock(true);
    public static void main(String[] args) {
        // 定义线程任务
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // 加锁
                lock.lock();
                try {
                    // 打印执行线程的名字
                    System.out.println("线程:" + Thread.currentThread().getName());
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            }
        };
        // 创建多个线程
        for (int i = 0; i < 10; i++) {
            new Thread(runnable).start();
        }
    }
}
Nach dem Login kopieren
Was sind die häufigsten Fallstricke von ReentrantLock in Java?Wie aus dem ersichtlich ist Im obigen Quellcode erstellt ReentrantLock standardmäßig eine unfaire Sperre. Wenn der Wert des Konstruktionsparameters beim Erstellen explizit auf true gesetzt wird, wird eine faire Sperre erstellt.

2. Geben Sie die Sperre endlich frei.

Wenn Sie ReentrantLock verwenden, müssen Sie daran denken, die Sperre aufzuheben, da die Sperre sonst ständig belegt ist und andere Threads, die die Sperre verwenden, ewig warten. Daher verwenden wir ReentrantLock Achten Sie dabei unbedingt darauf, die Sperre endgültig zu lösen, damit Sie sicher sein können, dass die Sperre gelöst wird.

Gegenbeispiel

 public ReentrantLock() {
     sync = new NonfairSync();
 }
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}
Nach dem Login kopieren

Das Ausführungsergebnis des obigen Programms lautet wie folgt:

Aus den obigen Ergebnissen ist ersichtlich, dass die Sperre beim Auftreten einer Ausnahme nicht normal aufgehoben wird führt dazu, dass sich andere Threads, die die Sperre verwenden, dauerhaft im Wartezustand befinden.

Positives Beispiel

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 创建锁对象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 加锁操作
        lock.lock();
        System.out.println("Hello,ReentrantLock.");
        // 此处会报异常,导致锁不能正常释放
        int number = 1 / 0;
        // 释放锁
        lock.unlock();
        System.out.println("锁释放成功!");
    }
}
Nach dem Login kopieren

Was sind die häufigsten Fallstricke von ReentrantLock in Java?Die Ausführungsergebnisse des obigen Programms lauten wie folgt:

Aus den obigen Ergebnissen ist ersichtlich, dass zwar eine Ausnahme in der Methode auftritt, diese jedoch keine Auswirkungen hat Geben Sie den Vorgang der ReentrantLock-Sperre frei, damit andere Threads, die diese Sperre verwenden, sie erhalten und normal ausführen können.

3. Die Sperre kann nicht mehrmals aufgehoben werdenDie Anzahl der Sperrvorgänge und die Anzahl der Entsperrvorgänge müssen eins zu eins übereinstimmen und eine Sperre kann nicht mehrmals aufgehoben werden, da dies dazu führt, dass das Programm einen Fehler meldet.

Was sind die häufigsten Fallstricke von ReentrantLock in Java?Gegenbeispiel

Eine Sperre entspricht zwei Entsperrvorgängen, wodurch das Programm einen Fehler meldet und die Ausführung abbricht. Der Beispielcode lautet wie folgt:

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 创建锁对象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        // 加锁操作
        lock.lock();
        try {
            System.out.println("Hello,ReentrantLock.");
            // 此处会报异常
            int number = 1 / 0;
        } finally {
            // 释放锁
            lock.unlock();
            System.out.println("锁释放成功!");
        }
    }
}
Nach dem Login kopieren

Die Ausführungsergebnisse des obigen Programms sind wie folgt :

Aus den obigen Ergebnissen können Sie erkennen, dass das Programm beim Ausführen der zweiten Entsperrung einen Fehler gemeldet und die Ausführung abgebrochen hat, was dazu führte, dass der Code nach der Ausnahme nicht normal ausgeführt wurde.

4.lock 不要放在 try 代码内

在使用 ReentrantLock 时,需要注意不要将加锁操作放在 try 代码中,这样会导致未加锁成功就执行了释放锁的操作,从而导致程序执行异常。

反例

import java.util.concurrent.locks.ReentrantLock;
public class LockExample {
    // 创建锁对象
    private static final ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        try {
            // 此处异常
            int num = 1 / 0;
            // 加锁操作
            lock.lock();
        } finally {
            // 释放锁
            lock.unlock();
            System.out.println("锁释锁");
        }
        System.out.println("程序执行完成.");
    }
}
Nach dem Login kopieren

以上程序的执行结果如下: 

Was sind die häufigsten Fallstricke von ReentrantLock in Java?

 从上述结果可以看出,如果将加锁操作放在 try 代码中,可能会导致两个问题:

  • 未加锁成功就执行了释放锁的操作,从而导致了新的异常;

  • 释放锁的异常会覆盖程序原有的异常,从而增加了排查问题的难度。

Das obige ist der detaillierte Inhalt vonWas sind die häufigsten Fallstricke von ReentrantLock in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!