Heim  >  Artikel  >  Java  >  Was ist eine Sperre in Java? Detaillierte Einführung in Sperren in Java

Was ist eine Sperre in Java? Detaillierte Einführung in Sperren in Java

不言
不言Original
2018-09-27 17:16:3510333Durchsuche

Der Inhalt dieses Artikels befasst sich mit der Frage, was eine Sperre in Java ist. Die ausführliche Einführung von Sperren in Java hat einen gewissen Referenzwert. Ich hoffe, dass sie für Sie hilfreich ist.

1. Einführung

Die Sperrung wird in JAVA über das Synchronized-Schlüsselwort implementiert und Verwandte Klassen unter dem Paket java.util.concurrent.

Relevante API, die von Java zum Implementieren von Sperren bereitgestellt wird:

Was ist eine Sperre in Java? Detaillierte Einführung in Sperren in Java

Lock bietet ein breiteres Spektrum an Sperrvorgängen als die Verwendung synchronisierter Synchronisationsmethoden und Synchronisationsanweisungsblöcke.

2.java.util.concurrent-Paket

Schnittstelle sperren

//试图获取锁.
void lock() 
 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
         
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()

ReentranLock-Klasse

Konstruktionsmethode

//创建一个 ReentrantLock 的实例.
ReentrantLock()          
//创建一个具有给定公平策略的 ReentrantLock实例.
ReentrantLock(boolean fair)

Faire Sperre: Multithreads erwerben Sperren in der Reihenfolge, in der sie Sperren beantragen.

Unfaire Sperre: Multithreads erwerben Sperren nicht in der Reihenfolge, in der sie Sperren beantragen, d. h. der Thread, der die Sperre zuerst beantragt, ist möglicherweise nicht der erste, der sie erhält das Schloss.

Zusammenfassung gängiger Methoden

//试图获取锁.   void lock() //如果当前线程未被中断,则获取锁.void lockInterruptibly() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁.boolean tryLock() //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁.  boolean tryLock(long timeout, TimeUnit unit) //试图释放此锁.    void unlock() //返回用来与此 Lock 实例一起使用的 Condition 实例.Condition newCondition() //如果此锁的公平设置为 true,则返回 true.boolean isFair() //返回正等待获取此锁的线程估计数.int getQueueLength()     //返回等待与此锁相关的给定条件的线程估计数.int getWaitQueueLength(Condition condition) //返回标识此锁及其锁定状态的字符串.String  toString()

Bedingungsschnittstelle

//使当前线程在接收到信号前或被中断前一直保持等待状态.
void await()
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(TimeUnit为时间单位).
boolean await(long time, TimeUnit unit)
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(单位为毫秒).
long awaitNanos(long nanosTimeout)
 
//使当前线程在接收到信号前或被中断前或达到最后日期期限前一直保持等待状态.
boolean awaitUntil(Date deadline)
 
//唤醒一个在该Condition实例等待的线程.
void signal()
 
//唤醒所有在该Condition实例等待的线程.         
void signalAll()

Eine Bedingungsinstanz wird an eine Lock-Instanz als Bedingungssteuerung der Lock-Instanz gebunden.

Bevor Sie die von der Bedingungsschnittstelle deklarierten Methoden aufrufen, müssen Sie die Sperre für diese Bedingung erhalten.

Nachdem die Methoden „await()“, „await(long time, TimeUnit-Einheit), „awaitNanos(long nanosTimeout)“ und „awaitUntil(Date Deadline)“ aufgerufen wurden, wird dies geschehen Bedingungsbezogene Sperren werden atomar aufgehoben.

Nachdem die Methoden signal() und signalAll() aufgerufen wurden, muss der aufgeweckte Thread die Sperre erneut erlangen, bevor er von der Methode waiting() zurückkehrt.

Verwendungsbeispiel:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 17:36
* @Description:
*/
public class TestReentranLock implements Runnable{

    /**
     * 可重入锁
     */
    private ReentrantLock reentrantLock = new ReentrantLock(true);

    /**
     * 锁条件
     */
    private Condition condition = reentrantLock.newCondition();

    /**
     * 业务处理
     */
    public void service(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取锁");
        reentrantLock.lock();
        System.out.println(threadName+":获取锁成功");
        try {
            System.out.println(threadName+":使当前线程等待,并释放锁资源。");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
            System.out.println(threadName+":释放锁");
        }
    }

    /**
     * 唤醒在该Condition实例等待的线程
     */
    public void signalAll(){
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();
    }

    @Override
    public void run() {
        service();
    }

    public static void main(String[] args) {

        TestReentranLock testReentranLock = new TestReentranLock();

        Thread threadA = new Thread(testReentranLock,"线程A");
        Thread threadB = new Thread(testReentranLock,"线程B");
        Thread threadC = new Thread(testReentranLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        testReentranLock.signalAll();

    }

}

Fair Lock-Ausführungsergebnis:

线程B:尝试获取锁
线程A:尝试获取锁
线程B:获取锁成功
线程C:尝试获取锁
线程B:使当前线程等待,并释放锁资源。
线程A:获取锁成功
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:释放锁
线程C:释放锁
线程A:释放锁

Unfaires Sperrausführungsergebnis:

线程B:尝试获取锁
线程A:尝试获取锁
线程A:获取锁成功
线程C:尝试获取锁
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:获取锁成功
线程B:使当前线程等待,并释放锁资源。
线程A:释放锁
线程B:释放锁
线程C:释放锁

ReadWriteLock-Schnittstelle

//返回用于读取操作的锁.
Lock readLock()          
//返回用于写入操作的锁.
Lock writeLock()

ReentrantReadWriteLock-Klasse

Konstruktionsmethode

//创建一个ReentrantReadWriteLock实例.
ReentrantReadWriteLock()        
//创建一个具有给定公平策略的ReentrantReadWriteLock实例.
ReentrantReadWriteLock(boolean fair)

Zusammenfassung gängiger Methoden

//返回用于读取操作的锁.
Lock ReentrantReadWriteLock。ReadLock。readLock()   
//返回用于写入操作的锁.
Lock ReentrantReadWriteLock。WriteLock。writeLock()
//返回等待获取读取或写入锁的线程估计数目.
int getQueueLength()
//如果此锁的公平设置为 true,则返回 true.
boolean isFair()
//返回标识此锁及其锁状态的字符串.
String toString()

Statische innere Klasse ReadLock/WriteLock

Zusammenfassung allgemeiner Methoden

//试图获取锁.
void lock() 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
          
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()
 
//返回标识此锁及其锁状态的字符串.
String toString()

Da ReadLock keine Bedingungen unterstützt, wenn ReadLock aufgerufen wird Die Methode newCondition() löst eine UnsupportedOperationException-Ausnahme aus.

Lesesperren und Schreibsperren mit ReentrantReadWriteLock folgen der Lese-/Lesefreigabe, dem gegenseitigen Schreib-/Schreibausschluss und dem gegenseitigen Lese-/Schreibausschluss.

Verwendungsbeispiel:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 18:04
* @Description:
*/
public class TestReentrantReadWriteLock implements Runnable{


    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);

    /**
     * 读锁
     */
    private Lock readLock = reentrantReadWriteLock.readLock();

    /**
     * 写锁
     */
    private Lock writeLock = reentrantReadWriteLock.writeLock();

    /**
     * 读取操作
     */
    public void reading(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取读锁");
        readLock.lock();
        System.out.println(threadName+":获取读锁成功");
        System.out.println(threadName+":释放读锁");
        readLock.unlock();
    }

    /**
     * 写入操作
     */
    public void writing(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取写锁");
        writeLock.lock();
        System.out.println(threadName+":获取写锁成功");
        System.out.println(threadName+":释放写锁");
        writeLock.unlock();
    }


    public static void main(String[] args) {
        TestReentrantReadWriteLock testReentrantReadWriteLock = new TestReentrantReadWriteLock();

        Thread threadA = new Thread(testReentrantReadWriteLock,"线程A");
        Thread threadB = new Thread(testReentrantReadWriteLock,"线程B");
        Thread threadC = new Thread(testReentrantReadWriteLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();
    }

}

Ergebnis der gemeinsamen Ausführung lesen:

@Overridepublic void run() {     
 //读读共享      
 reading();
}
rrree

Die Lesesperre kann von mehreren Threads gleichzeitig erworben werden, was die Leseeffizienz verbessern kann (obwohl sie nicht freigegeben werden muss, wenn nur die Lesesperre verwendet wird). Dies wirkt sich auf den Erwerb der Schreibsperre aus: Kann von einem Thread abgerufen werden.

Ergebnis der Ausführung des gegenseitigen Ausschlusses beim Lesen und Schreiben:

线程A:尝试获取读锁
线程B:尝试获取读锁
线程A:获取读锁成功
线程A:释放读锁
线程C:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程B:获取读锁成功
线程B:释放读锁
rrree

Schreiben beim Lesen nicht möglich. Sie können beim Schreiben nicht lesen, d. h. wenn die Schreibsperre derzeit von einem Thread gehalten wird, müssen Sie darauf warten, dass die Schreibsperre aufgehoben wird. Wenn Sie eine Schreibsperre erwerben, wird die Lesesperre derzeit gehalten Durch einen Thread warten Sie darauf, dass die Lesesperre aufgehoben wird und die Schreibsperre nicht gehalten wird.

3. Klassifizierung von Sperren in Java

Die Sperren in Java entsprechen Das Schloss ist nach Merkmalen unterteilt.

Gerechte Sperre/unfaire Sperre

Gerechte Sperre: Für Sperren gelten Multithreads entsprechend erwerben Schlösser in der richtigen Reihenfolge.

Unfaire Sperre: Multithreads erwerben Sperren nicht in der Reihenfolge, in der sie Sperren beantragen, d. h. der Thread mit der ersten lock() ist nicht der erste, der die Sperren erhält sperren.

Für ReentranLock- und ReentrantReadWriteLock-Sperren können Sie durch die Konstruktionsmethode festlegen, ob es sich um faire oder unfaire Sperren handelt.

Für das Synchronized-Schlüsselwort handelt es sich um eine unfaire Sperre.

Gemeinsame Sperre/exklusive Sperre

Gemeinsame Sperre: bedeutet, dass die Sperre von mehreren Threads gleichzeitig gehalten werden kann. Es handelt sich um eine gemeinsame Sperre.

Exklusive Sperre: bedeutet, dass die Sperre nur von einem Thread gleichzeitig gehalten werden kann. Bei ReentranLock, WriteLock und Synchronized handelt es sich um eine exklusive Sperre.

Optimistische Sperre/pessimistische Sperre

Optimistische Sperre und pessimistische Sperre sind keine spezifische Sperre Eigenschaften, sondern die Perspektive bei der Betrachtung der Parallelität.

Optimistische Sperre: Es wird davon ausgegangen, dass gleichzeitige Vorgänge die Integrität der Daten nicht beeinträchtigen, sodass keine Sperre erforderlich ist.

Pessimistische Sperre: Es wird angenommen, dass gleichzeitige Vorgänge definitiv die Integrität der Daten beeinträchtigen, daher muss eine Sperre durchgeführt werden.

Der Lesevorgang eignet sich für optimistisches Sperren, dh es wird kein Sperren durchgeführt, was die Effizienz beim Lesen von Daten verbessern kann.

Schreibvorgänge eignen sich für pessimistische Sperren, dh es muss eine Sperre durchgeführt werden.

Segmentierte Sperre

Segmentierte Sperre bezieht sich auf das Design der Sperre, das gleichzeitige Vorgänge durch Verfeinerung der Granularität der Sperre steuert . Das Segment in Javas ConcurrentHashMap implementiert gleichzeitige Vorgänge durch den Entwurf von Segmentsperren.

Bias Lock/Lightweight Lock/Heavyweight Lock

Bias Lock, Lightweight Lock und Heavyweight Lock sind alles Fingerschlösser. Die verschiedenen Zustände gelten für Synchronisiertes Schlüsselwort.

Voreingenommene Sperre: bedeutet, dass die synchronisierte Methode oder der synchronisierte Anweisungsblock immer nur von einem Thread gehalten wird. Zu diesem Zeitpunkt ist der Status der Sperre voreingenommene Sperre, was die Kosten senkt die Sperre für den Thread zu erlangen.

Lightweight-Sperre: Wenn der Sperrstatus eine voreingenommene Sperre ist und andere Threads darauf zugreifen, versuchen andere Threads, die Sperre durch Drehen zu erhalten. Der Status ist eine leichte Sperre.

Spin versucht, die Sperre durch eine bestimmte Anzahl von Schleifen zu erhalten. Der Nachteil besteht darin, dass sie CPU-Leistung verbraucht.

Heavyweight-Sperre: Wenn der Sperrstatus eine Lightweight-Sperre ist und andere Threads die Sperre nach dem Drehen nicht erhalten haben, ist der Sperrstatus eine Heavyweight-Sperre Threads gelangen in den Blockierungszustand und die Leistung wird reduziert.

Wenn der Sperrstatus eine voreingenommene Sperre ist, ist die Leistung am höchsten, und wenn die Sperre schwergewichtig ist, ist die Leistung am niedrigsten.

Das obige ist der detaillierte Inhalt vonWas ist eine Sperre in Java? Detaillierte Einführung in Sperren in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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