Heim  >  Artikel  >  Java  >  Was sind die Mechanismen verschiedener Sperren in Java?

Was sind die Mechanismen verschiedener Sperren in Java?

王林
王林nach vorne
2023-04-20 08:34:121061Durchsuche

Vorwort

Zusammenfassung gängiger Sperren in Java

Unterscheiden Sie die einzelnen Sperrmechanismen und wie Sie sie verwenden.

Möchten Sie nach dem Sperren der Synchronisierungsressource blockieren? Wenn Sie nicht blockieren, können Sie eine Spin-Sperre verwenden WiedereintrittssperreLese-/Schreibsperre (gemeinsame Sperre zum Schreiben)Gerechte Sperre und unfaire Sperre
Verwendungsmethode: Optimistisch Sperre und pessimistische Sperre
Ein Thread und mehrere Prozesse erhalten dieselbe Sperre
Mehrere Threads teilen sich eine Sperre
Sollten mehrere Threads um die Warteschlange konkurrieren

1. Optimistische Sperre und pessimistische Sperre

Pessimistische Sperre: Bei der Ausführung können nicht mehrere Personen gleichzeitig ausgeführt werden. In herkömmlichen relationalen Datenbanken werden viele solcher Sperrmechanismen verwendet, z. B. Zeilensperren, Tabellensperren, Lesesperren, Schreibsperren usw., die alle vor dem Betrieb gesperrt werden Wenn die Nummern konsistent sind oder nicht, werden die Daten mit einer Version hinzugefügt, die Daten werden synchron aktualisiert und die Versionsnummer wird hinzugefügt. Es wird nicht gesperrt, die Versionsnummer kann ermittelt werden und kann von mehreren Personen bedient werden, ähnlich wie beim Ticketraub im Leben. Jedes Mal, wenn Sie die Daten abrufen, denken Sie, dass andere sie nicht ändern werden, sodass sie nicht gesperrt werden. Beim Aktualisieren können Sie jedoch beurteilen, ob andere die Daten in diesem Zeitraum aktualisiert haben Zahlen. Optimistisches Sperren eignet sich für Anwendungstypen mit mehreren Lesevorgängen, wodurch der Durchsatz verbessert werden kann. Redis verwendet diesen Check-and-Set-Mechanismus, um Transaktionen zu implementieren. #

Demonstrieren Sie pessimistische Sperren und optimistische Sperren durch bestimmte Fälle

Im Redis-Framework

Vor der Ausführung von Multi Führen Sie den Befehl watch aus

Was sind die Mechanismen verschiedener Sperren in Java?

Wenn Sie jedoch auf einem anderen Server exec eingeben, wird ein Fehler angezeigt.

Da optimistisches Sperren verwendet wird, wird die Version angezeigt ändert sich nach der Änderung

Allgemein:#🎜 🎜#

Pessimistische Sperre: Wenn jede Person etwas alleine erledigt, sperren und entsperren. Lösen Sie das Problem der Parallelität. Es kann nur einzeln ausgeführt werden, was ineffizient ist.

Optimistische Sperre: Bei jeder Ausführung wird die Datenversionsnummer verglichen. Wer zuerst einreicht, reicht die Version zuerst ein Sperre: nicht in Ordnung, Sie können in die Warteschlange springen

Gerechte Sperre: relativ geringe EffizienzWas sind die Mechanismen verschiedener Sperren in Java?

Unfaire Sperre: hohe Effizienz, aber Threads neigen zum Verhungern

Durch diese Funktion Lock lock = new ReentrantLock(true);. Erstellen Sie eine Wiedereintrittssperre. True bedeutet faire Sperre, false bedeutet unfaire Sperre. Standardmäßige unfaire Sperre

Durch Anzeigen des Quellcodes

ReentrantLock(true) mit Parametern ist eine faire Sperre

ReentrantLock(false) ist eine unfaire Sperre

Rufen Sie hauptsächlich NonfairSync() und FairSync() auf

watch key1 [key2]

Geben Sie den Quellcode von unfair lock und fair lock an
  • Sehen Sie sich den Quellcode von fair an Sperre

    127.0.0.1:6379> flushdb
    OK
    127.0.0.1:6379> set add 100
    OK
    127.0.0.1:6379> watch add
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379(TX)> incrby add 20
    QUEUED
    127.0.0.1:6379(TX)> exec
    1) (integer) 120
    127.0.0.1:6379>

    Spezifische Operation durch Codebeispiele
  • public ReentrantLock() {
            sync = new NonfairSync();
        }
    
        /**
         * Creates an instance of {@code ReentrantLock} with the
         * given fairness policy.
         *
         * @param fair {@code true} if this lock should use a fair ordering policy
         */
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }
  • Die Ergebnis-Screenshots sind wie folgt

sind alle A-Threads Ausführung, aber der BC-Thread wurde nicht ausgeführt und es erscheint eine unfaire Sperre

Um seine Einstellungen gezielt zu ändern, können Sie den Code über eine parametrisierte Konstruktionsmethode in der wiedereintrittsfähigen Sperre #🎜 ändern 🎜#

Für privates Finale ReentrantLock lock = new ReentrantLock(true);

Der Code-Screenshot ist

3. Wiedereintrittssperre# 🎜🎜#

Wiedereintrittssperren werden auch rekursive Sperren genannt

Und mit den Wiedereintrittssperren können Sie in die innere Struktur gelangen, nachdem Sie die erste geknackt haben

static final class FairSync extends Sync {
   private static final long serialVersionUID = -3000897897090466540L;

  /**
  * Acquires only if reentrant or queue is empty.
   */
  final boolean initialTryLock() {
   Thread current = Thread.currentThread();
   int c = getState();
   if (c == 0) {
   if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
     setExclusiveOwnerThread(current);
      return true;
    }
    } else if (getExclusiveOwnerThread() == current) {
      if (++c < 0) // overflow
          throw new Error("Maximum lock count exceeded");
         setState(c);
         return true;
       }
    return false;
}
# 🎜🎜#synchronisiert (o) steht für das Sperren des Codeblocks im aktuellen {}

Die oben genannten sind synchronisierte Sperrmechanismen

Im Folgenden wird der Sperrmechanismus erläutertWas sind die Mechanismen verschiedener Sperren in Java?

//第一步  创建资源类,定义属性和和操作方法
class LTicket {
    //票数量
    private int number = 30;

    //创建可重入锁
    private final ReentrantLock lock = new ReentrantLock(true);
    //卖票方法
    public void sale() {
        //上锁
        lock.lock();
        try {
            //判断是否有票
            if(number > 0) {
                System.out.println(Thread.currentThread().getName()+" :卖出"+(number--)+" 剩余:"+number);
            }
        } finally {
            //解锁
            lock.unlock();
        }
    }
}

public class LSaleTicket {
    //第二步 创建多个线程,调用资源类的操作方法
    //创建三个线程
    public static void main(String[] args) {

        LTicket ticket = new LTicket();

new Thread(()-> {
    for (int i = 0; i < 40; i++) {
        ticket.sale();
    }
},"AA").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"BB").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"CC").start();
    }
}

Verschachtelte Sperren in derselben Sperre können immer noch ausgegeben werden, wenn die interne verschachtelte Sperre nicht entsperrt ist. Wenn Sie jedoch aus dem Thread springen und einen anderen Thread ausführen, führt dies zu einem Deadlock

Be vorsichtig Die Konzepte des Sperrens und Entsperrens müssen mit

4 geschrieben werden. Lese-/Schreibsperre (gemeinsame Sperre und exklusive Sperre)

#🎜 🎜# Die Lesesperre ist eine gemeinsame Sperre und die Schreibsperre ist eine exklusive Sperre. Lese-/Schreibsperren verwalten eine Reihe von Sperren, eine davon ist eine schreibgeschützte Sperre und die andere ist eine Schreibsperre.

Was sind die Mechanismen verschiedener Sperren in Java?

Lese-/Schreibsperre: Auf eine Ressource können mehrere Lese-Threads oder ein Schreib-Thread zugreifen, Lese- und Schreib-Threads können jedoch nicht gleichzeitig vorhanden sein. Gegenseitiger Schreibausschluss, gemeinsame Lese-/Lesesperre (exklusive Schreibsperre, gemeinsame Lesesperre, Priorität der Schreibsperre ist höher als die Lesesperre)

Lese-/Schreibsperre ReentrantReadWriteLock

Die Lesesperre ist ReentrantReadWriteLock.ReadLock, readLock()-Methode

Die Schreibsperre ist ReentrantReadWriteLock.WriteLock, writeLock()-Methode

Erstellen Sie ein Lese-/Schreibsperrobjekt, privat ReadWriteLock rwLock = neues ReentrantReadWriteLock ();

#🎜 🎜#Schreibsperre rwLock.writeLock().lock();, entsperren rwLock.writeLock().unlock();

Lesesperre rwLock.readLock() .lock() ;, Entsperren ist rwLock.readLock().unlock();

Fallanalyse:

Multithreading simulieren, um Daten in der Karte abzurufen und zu lesen# 🎜🎜##🎜 🎜#Der vollständige Code lautet wie folgt

Object o = new Object();
new Thread(()->{
    synchronized(o) {
        System.out.println(Thread.currentThread().getName()+" 外层");

        synchronized (o) {
            System.out.println(Thread.currentThread().getName()+" 中层");

            synchronized (o) {
                System.out.println(Thread.currentThread().getName()+" 内层");
            }
        }
    }

},"t1").start();
Was sind die Mechanismen verschiedener Sperren in Java?5. Mutex-Sperre

Mutex-Sperre ist eine herkömmliche Implementierung einer exklusiven Sperre, was bedeutet, dass eine bestimmte Ressource Ermöglicht nur einem Besucher gleichzeitig den Zugriff mit Einzigartigkeit und Exklusivität.

它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名

通俗的来说就是一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务。

其特点:

  1. 持有锁时间等待过长,消耗CPU

  2. 无法满足等待时间最长的线程优先获取锁。不公平的锁就会存在“线程饥饿”问题

  3. 自旋锁不会使线程状态发生切换,处于用户态(不会到内核态进行线程的状态转换),一直都是活跃,不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

其模拟算法如下

do{
	b=1;
	while(b){
		lock(bus);
		b = test_and_set(&lock);
		unlock(bus);
	}
	//临界区
	//lock = 0;
	//其余部分
}while(1)

7. 无锁 / 偏向锁 / 轻量级锁 / 重量级锁

  • 无锁:没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功

  • 偏向锁:是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,降低获取锁的代价

  • 轻量级锁:锁是偏向锁的时候,被另外的线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能

  • 重量级锁:线程并发加剧,线程的自旋超过了一定次数,或者一个线程持有锁,一个线程在自旋,还有线程要访问

Das obige ist der detaillierte Inhalt vonWas sind die Mechanismen verschiedener Sperren in Java?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen