Maison > Java > javaDidacticiel > Qu'est-ce qu'un verrou en Java ? Introduction détaillée aux verrous en Java

Qu'est-ce qu'un verrou en Java ? Introduction détaillée aux verrous en Java

不言
Libérer: 2018-09-27 17:16:34
original
10377 Les gens l'ont consulté

Le contenu de cet article porte sur ce qu'est un verrou en Java ? L'introduction détaillée des verrous en Java a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère qu'elle vous sera utile.

1 Introduction

Le verrouillage est implémenté en JAVA via le mot-clé synchronisé et associé. classes sous le package java.util.concurrent.

API pertinente fournie par Java pour implémenter le verrouillage :

Quest-ce quun verrou en Java ? Introduction détaillée aux verrous en Java

Lock fournit une gamme d'opérations de verrouillage plus large que l'utilisation de méthodes de synchronisation synchronisées et de blocs d'instructions de synchronisation.

Paquet 2.java.util.concurrent

Interface de verrouillage

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

Classe ReentranLock

Méthode de construction

//创建一个 ReentrantLock 的实例.
ReentrantLock()          
//创建一个具有给定公平策略的 ReentrantLock实例.
ReentrantLock(boolean fair)
Copier après la connexion

Verrouillage équitable : les multithreads acquièrent des verrous dans l'ordre dans lequel ils demandent des verrous.

Verrouillage injuste : les multithreads n'acquièrent pas les verrous dans l'ordre dans lequel ils demandent les verrous, c'est-à-dire que le thread qui demande le verrou en premier peut ne pas être le premier à acquérir la serrure.

Résumé des méthodes courantes

//试图获取锁.   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()
Copier après la connexion

Interface de condition

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

Une instance de Condition sera liée à une instance de Lock en tant que contrôle de condition de l'instance de Lock.

Avant d'appeler les méthodes déclarées par l'interface Condition, vous devez obtenir le verrou lié à cette Condition.

Après l'appel des méthodes wait(), wait(long time, TimeUnit unit), waitNanos(long nanosTimeout), waitUntil(Date date limite), cela va Les verrous liés à la condition seront libérés de manière atomique.

Après l'appel des méthodes signal() et signalAll(), le thread réveillé doit réacquérir le verrou avant de revenir de la méthode wait().

Exemple d'utilisation :

/**
* @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();

    }

}
Copier après la connexion

Résultat de l'exécution du verrouillage équitable :

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

Résultat d'exécution du verrouillage injuste :

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

Interface ReadWriteLock

//返回用于读取操作的锁.
Lock readLock()          
//返回用于写入操作的锁.
Lock writeLock()
Copier après la connexion

Classe ReentrantReadWriteLock

Méthode de construction

//创建一个ReentrantReadWriteLock实例.
ReentrantReadWriteLock()        
//创建一个具有给定公平策略的ReentrantReadWriteLock实例.
ReentrantReadWriteLock(boolean fair)
Copier après la connexion

Résumé des méthodes courantes

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

Classe interne statique ReadLock/WriteLock

Résumé de la méthode commune

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

Étant donné que ReadLock ne prend pas en charge les conditions, une UnsupportedOperationException sera levée lorsque la méthode newCondition() de ReadLock est appelée.

Les verrous en lecture et en écriture utilisant ReentrantReadWriteLock suivront le partage en lecture-lecture, l'exclusion mutuelle en écriture-écriture et l'exclusion mutuelle en lecture-écriture.

Exemple d'utilisation :

/**
* @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();
    }

}
Copier après la connexion

Lire le résultat d'exécution partagé :

@Overridepublic void run() {     
 //读读共享      
 reading();
}
Copier après la connexion
线程A:尝试获取读锁
线程B:尝试获取读锁
线程A:获取读锁成功
线程A:释放读锁
线程C:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程B:获取读锁成功
线程B:释放读锁
Copier après la connexion

Le verrou de lecture peut être acquis par plusieurs threads en même temps, ce qui peut améliorer l'efficacité de la lecture (même s'il n'est pas nécessaire qu'il soit libéré lorsque seul le verrou en lecture est utilisé, mais cela affectera l'acquisition du verrou en écriture)

Résultat de l'exécution du mutex en écriture :

@Overridepublic void run() {  
    //写写互斥     
    writing();
}
Copier après la connexion
线程A:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程C:尝试获取写锁
线程A:释放写锁
线程B:获取写锁成功
线程B:释放写锁
线程C:获取写锁成功
线程C:释放写锁
Copier après la connexion

Un verrou en écriture ne peut être acquis que par un seul thread à la fois.

Lire et écrire le résultat de l'exécution du mutex :

@Overridepublic void run() {      
   //读写互斥      
   writing();
  reading();
}
Copier après la connexion
线程A:尝试获取写锁
线程C:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程A:释放写锁
线程A:尝试获取读锁
线程C:获取写锁成功
线程C:释放写锁
线程C:尝试获取读锁
线程B:获取写锁成功
线程B:释放写锁
线程B:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程A:获取读锁成功
线程A:释放读锁
线程B:获取读锁成功
线程B:释放读锁
Copier après la connexion

Lire Vous ne pouvez pas écrire lorsque vous écrivez, et vous ne pouvez pas lire lorsque vous écrivez. Autrement dit, lorsque vous obtenez un verrou en lecture, si le verrou en écriture est détenu par un thread à ce moment-là, vous attendrez que le verrou en écriture soit libéré. . Lorsque vous obtenez un verrou en écriture, si le verrou en lecture est détenu par un thread à ce moment-là, vous attendez que le verrou en lecture soit libéré et que le verrou en écriture ne soit pas maintenu.

3. Classification des verrous en Java

Les verrous en Java sont selon la serrure divisée par caractéristiques.

Verrouillage équitable/verrouillage injuste

Verrouillage équitable : plusieurs threads s'appliquent aux verrous selon acquérir des serrures dans l'ordre.

Verrouillage injuste : les multithreads n'acquièrent pas les verrous dans l'ordre dans lequel ils demandent les verrous, c'est-à-dire que le thread avec le premier verrou() n'est pas le premier à acquérir le verrouillage.

Pour les verrous ReentranLock et ReentrantReadWriteLock, vous pouvez définir s'il s'agit de verrous équitables ou de verrous injustes via la méthode de construction.

Pour le mot-clé Synchronisé, il s'agit d'un verrouillage injuste.

Verrouillage partagé/verrouillage exclusif

Verrouillage partagé : signifie que le verrou peut être détenu par plusieurs threads en même temps. Pour ReadLock, c'est un verrou partagé.

Verrou exclusif : signifie que le verrou ne peut être détenu que par un seul thread à la fois. Pour ReentranLock, WriteLock et Synchronized, il s'agit d'un verrou exclusif.

Verrouillage optimiste/verrouillage pessimiste

Le verrouillage optimiste et le verrouillage pessimiste ne sont pas spécifiques au verrouillage caractéristiques, mais la perspective lorsque l’on regarde la concurrence.

Verrouillage optimiste : on pense que les opérations simultanées n'affecteront pas l'intégrité des données, aucun verrouillage n'est donc requis.

Verrouillage pessimiste : on pense que les opérations simultanées affecteront certainement l'intégrité des données, un verrouillage doit donc être effectué.

L'opération de lecture convient au verrouillage optimiste, c'est-à-dire qu'aucun verrouillage n'est effectué, ce qui peut améliorer l'efficacité de la lecture des données.

Les opérations d'écriture conviennent au verrouillage pessimiste, c'est-à-dire que le verrouillage doit être effectué.

Verrouillage segmenté

Le verrouillage segmenté fait référence à la conception du verrou, qui contrôle les opérations simultanées en affinant la granularité du verrou , le segment de ConcurrentHashMap de Java implémente des opérations simultanées grâce à la conception de verrous de segment.

Verrouillage de biais/verrouillage léger/verrouillage lourd

Le verrouillage de biais, le verrouillage léger et le verrouillage lourd sont tous des verrouillages à doigt. Les différents états sont pour le Mot-clé synchronisé.

Verrou biaisé : signifie que la méthode synchronisée ou le bloc d'instructions synchronisées est toujours détenu par un seul thread. À ce stade, le statut du verrou est un verrouillage biaisé, ce qui réduira le coût. d'acquérir le verrou pour le thread.

Verrouillage léger : lorsque l'état du verrouillage est un verrouillage biaisé, s'il est accédé par d'autres threads, d'autres threads tenteront d'acquérir le verrou en tournant. L'état est un verrouillage léger.

Spin tente d'acquérir le verrou en bouclant un certain nombre de fois. Cette méthode ne bloque pas le thread. L'inconvénient est qu'elle consomme les performances du processeur.

Verrouillage lourd : lorsque l'état du verrou est un verrou léger, si d'autres threads n'ont pas acquis le verrou après la rotation, alors l'état du verrou est un verrou lourd. À ce moment-là, autre. les threads entreront dans l’état de blocage et les performances seront réduites.

Lorsque l'état de verrouillage est un verrouillage biaisé, les performances sont les plus élevées, et lorsque le verrouillage est lourd, les performances sont les plus faibles.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal