Maison Java javaDidacticiel Java 线程状态之 BLOCKED

Java 线程状态之 BLOCKED

Nov 22, 2016 pm 04:20 PM
java

BLOCKED 状态的定义

前面已经说过 BLOCKED(阻塞) 的简单定义为:

一个正在阻塞等待一个监视器锁的线程处于这一状态。(A thread that is blocked waiting for a monitor lock is in this state.)

更加详细的定义可以参考 Thread.State 中的 javadoc:

/**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
        BLOCKED,
Copier après la connexion

这句话很长,可以拆成两个简单句来理解。

A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method。

一个处于 blocked 状态的线程正在等待一个监视器锁以进入一个同步的块或方法。

A thread in the blocked state is waiting for a monitor lock to reenter a synchronized block/method after calling Object.wait。

一个处于 blocked 状态的线程正在等待一个监视器锁,在其调用 Object.wait 方法之后,以再次进入一个同步的块或方法。

进入(enter)同步块时阻塞

先说第一句,这个比较好理解。

监视器锁用于同步访问,以达到多线程间的互斥。所以一旦一个线程获取锁进入同步块,在其出来之前,如果其它线程想进入,就会因为获取不到锁而阻塞在同步块之外,这时的状态就是 BLOCKED。

注:这一状态的进入及解除都不受我们控制,当锁可用时,线程即从阻塞状态中恢复。

我们可以用一些代码来演示这一过程:

@Test
public void testBlocked() throws Exception {
    class Counter {
        int counter;
        public synchronized void increase() {
            counter++;
            try {
                Thread.sleep(30000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    Counter c = new Counter();
    
    Thread t1 = new Thread(new Runnable() {
        public void run() {
            c.increase();
        }
    }, "t1线程");
    t1.start();
    
    Thread t2 = new Thread(new Runnable() {
        public void run() {
            c.increase();
        }
    }, "t2线程");
    t2.start();
    
    Thread.sleep(100); // 确保 t2 run已经得到执行
    assertThat(t2.getState()).isEqualTo(Thread.State.BLOCKED);
}
Copier après la connexion

以上定义了一个访问计数器 counter,有一个同步的 increase 方法。t1 线程先进入,然后在同步块里面睡觉,导致锁迟迟无法释放,t2 尝试执行同步方法时就因无法获取锁而被阻塞了。

VisualVM 监控显示了 t2 线程的状态:

55651933a6254.jpg

图上的“监视(monitor)”状态即为 BLOCKED 状态。可以看到在t1睡眠期间t2处于 BLOCKED 状态。

BLOCKED 状态可以视作是一种特殊的 WAITING,特指等待锁。

wait 之后重进入(reenter)同步块时阻塞

现在再次来看第二句:

2. A thread in the blocked state is waiting for a monitor lock to reenter a synchronized block/method after calling Object.wait。

一个处于 blocked 状态的线程正在等待一个监视器锁,在其调用 Object.wait 方法之后,以再次进入一个同步的块或方法。

这句话有点绕,也不好翻译成一句简洁的中文。如果没有对 wait 的相关背景有较好的理解,则不容易理解这句话。我们在此把它稍微展开讲一下。既然是 reenter,说明有两次 enter,这个过程是这样的:

调用 wait 方法必须在同步块中,即是要先获取锁并进入同步块,这是第一次 enter。

而调用 wait 之后则会释放该锁,并进入此锁的等待队列(wait set)中。

当收到其它线程的 notify 或 notifyAll 通知之后,等待线程并不能立即恢复执行,因为停止的地方是在同步块内,而锁已经释放了,所以它要重新获取锁才能再次进入(reenter)同步块,然后从上次 wait 的地方恢复执行。这是第二次 enter,所以叫 reenter。

但锁并不会优先给它,该线程还是要与其它线程去竞争锁,这一过程跟 enter 的过程其实是一样的,因此也可能因为锁已经被其它线程据有而导致 BLOCKED。

这一过程就是所谓的 reenter a synchronized block/method after calling Object.wait。

我们也用一段代码来演示这一过程:

@Test
public void testReenterBlocked() throws Exception {
    class Account {
        int amount = 100; // 账户初始100元
        public synchronized void deposit(int cash) { // 存钱
            amount += cash;
            notify();
            try {
                Thread.sleep(30000); // 通知后却暂时不退出
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        public synchronized void withdraw(int cash) { // 取钱
            while (cash > amount) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            amount -= cash;
        }
    }
    Account account = new Account();
    
    Thread withdrawThread = new Thread(new Runnable() {
        public void run() {
            account.withdraw(200);
        }
    }, "取钱线程");
    withdrawThread.start();
    
    Thread.sleep(100); // 确保取钱线程已经得到执行
    
    assertThat(withdrawThread.getState()).isEqualTo(Thread.State.WAITING);
    
    Thread depositThread = new Thread(new Runnable() {
        public void run() {
            account.deposit(100);
        }
    }, "存钱线程");
    Thread.sleep(10000); // 让取钱线程等待一段时间
    depositThread.start();

    Thread.sleep(300); // 确保取钱线程已经被存钱线程所通知到

    assertThat(withdrawThread.getState()).isEqualTo(Thread.State.BLOCKED);
}
Copier après la connexion

简要介绍一下以上代码场景:

有一个账户对象,有存钱(deposit)和取钱(withdraw)方法,初始金额100元。

取钱线程先启动,并进入(enter)同步块,试图取200元,发现钱不够,调用 wait,锁释放,线程挂起(WAITING 状态)。

10秒后存钱线程启动,存入钱并通知(notify)取钱线程,但之后继续在同步块中睡眠,导致锁没有释放。

取钱线程收到通知后,退出 WAITING 状态,但已经不持有锁,当试图重新进入(reenter)同步块以恢复执行时,因锁尚未被存钱线程释放,于是被阻塞(BLOCKED 状态)。

监控的显示:

55651933a6254.jpg

如图,取钱线程先是 WAITING,在收到通知因无法获取锁而阻塞(BLOCKED)。

总结

综合来看这两句话,两层意思,其实还是一个意思,简单地讲,就是enter,reenter 也还是 enter,概括地讲:

当因为获取不到锁而无法进入同步块时,线程处于 BLOCKED 状态。

如果有线程长时间处于 BLOCKED 状态,要考虑是否发生了死锁(deadlock)的状况。

BLOCKED 状态可以视作为一种特殊的 waiting,是传统 waiting 状态的一个细分:

QQ图片20161122092324.png

由于还没有讲到 WAITING 状态,而这里有涉及到了 wait 方法,所以上面对 wait 也稍微做了些分析,在下一章节,会更加详细的分析 WAITING 和 TIMED_WAITING 这两个状态。

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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

<🎜>: Dead Rails - Comment apprivoiser les loups
4 Il y a quelques semaines By DDD
Niveaux de force pour chaque ennemi et monstre de R.E.P.O.
4 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
<🎜>: Grow A Garden - Guide de mutation complet
2 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel Java
1661
14
Tutoriel PHP
1261
29
Tutoriel C#
1234
24
Break or Return of Java 8 Stream Forach? Break or Return of Java 8 Stream Forach? Feb 07, 2025 pm 12:09 PM

Java 8 présente l'API Stream, fournissant un moyen puissant et expressif de traiter les collections de données. Cependant, une question courante lors de l'utilisation du flux est: comment se casser ou revenir d'une opération FOREAK? Les boucles traditionnelles permettent une interruption ou un retour précoce, mais la méthode Foreach de Stream ne prend pas directement en charge cette méthode. Cet article expliquera les raisons et explorera des méthodes alternatives pour la mise en œuvre de terminaison prématurée dans les systèmes de traitement de flux. Lire plus approfondie: Améliorations de l'API Java Stream Comprendre le flux Forach La méthode foreach est une opération terminale qui effectue une opération sur chaque élément du flux. Son intention de conception est

PHP: un langage clé pour le développement Web PHP: un langage clé pour le développement Web Apr 13, 2025 am 12:08 AM

PHP est un langage de script largement utilisé du côté du serveur, particulièrement adapté au développement Web. 1.Php peut intégrer HTML, traiter les demandes et réponses HTTP et prend en charge une variété de bases de données. 2.PHP est utilisé pour générer du contenu Web dynamique, des données de formulaire de traitement, des bases de données d'accès, etc., avec un support communautaire solide et des ressources open source. 3. PHP est une langue interprétée, et le processus d'exécution comprend l'analyse lexicale, l'analyse grammaticale, la compilation et l'exécution. 4.PHP peut être combiné avec MySQL pour les applications avancées telles que les systèmes d'enregistrement des utilisateurs. 5. Lors du débogage de PHP, vous pouvez utiliser des fonctions telles que error_reportting () et var_dump (). 6. Optimiser le code PHP pour utiliser les mécanismes de mise en cache, optimiser les requêtes de base de données et utiliser des fonctions intégrées. 7

PHP vs Python: comprendre les différences PHP vs Python: comprendre les différences Apr 11, 2025 am 12:15 AM

PHP et Python ont chacun leurs propres avantages, et le choix doit être basé sur les exigences du projet. 1.Php convient au développement Web, avec une syntaxe simple et une efficacité d'exécution élevée. 2. Python convient à la science des données et à l'apprentissage automatique, avec une syntaxe concise et des bibliothèques riches.

PHP vs autres langues: une comparaison PHP vs autres langues: une comparaison Apr 13, 2025 am 12:19 AM

PHP convient au développement Web, en particulier dans le développement rapide et le traitement du contenu dynamique, mais n'est pas bon dans les applications de la science des données et de l'entreprise. Par rapport à Python, PHP présente plus d'avantages dans le développement Web, mais n'est pas aussi bon que Python dans le domaine de la science des données; Par rapport à Java, PHP fonctionne moins bien dans les applications au niveau de l'entreprise, mais est plus flexible dans le développement Web; Par rapport à JavaScript, PHP est plus concis dans le développement back-end, mais n'est pas aussi bon que JavaScript dans le développement frontal.

PHP vs Python: fonctionnalités et fonctionnalités de base PHP vs Python: fonctionnalités et fonctionnalités de base Apr 13, 2025 am 12:16 AM

PHP et Python ont chacun leurs propres avantages et conviennent à différents scénarios. 1.PHP convient au développement Web et fournit des serveurs Web intégrés et des bibliothèques de fonctions riches. 2. Python convient à la science des données et à l'apprentissage automatique, avec une syntaxe concise et une bibliothèque standard puissante. Lors du choix, il doit être décidé en fonction des exigences du projet.

Programme Java pour trouver le volume de la capsule Programme Java pour trouver le volume de la capsule Feb 07, 2025 am 11:37 AM

Les capsules sont des figures géométriques tridimensionnelles, composées d'un cylindre et d'un hémisphère aux deux extrémités. Le volume de la capsule peut être calculé en ajoutant le volume du cylindre et le volume de l'hémisphère aux deux extrémités. Ce tutoriel discutera de la façon de calculer le volume d'une capsule donnée en Java en utilisant différentes méthodes. Formule de volume de capsule La formule du volume de la capsule est la suivante: Volume de capsule = volume cylindrique volume de deux hémisphères volume dans, R: Le rayon de l'hémisphère. H: La hauteur du cylindre (à l'exclusion de l'hémisphère). Exemple 1 entrer Rayon = 5 unités Hauteur = 10 unités Sortir Volume = 1570,8 unités cubes expliquer Calculer le volume à l'aide de la formule: Volume = π × r2 × h (4

Impact de PHP: développement Web et au-delà Impact de PHP: développement Web et au-delà Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP: la fondation de nombreux sites Web PHP: la fondation de nombreux sites Web Apr 13, 2025 am 12:07 AM

Les raisons pour lesquelles PHP est la pile technologique préférée pour de nombreux sites Web incluent sa facilité d'utilisation, son soutien communautaire solide et son utilisation généralisée. 1) Facile à apprendre et à utiliser, adapté aux débutants. 2) Avoir une énorme communauté de développeurs et des ressources riches. 3) Largement utilisé dans WordPress, Drupal et d'autres plateformes. 4) Intégrez étroitement aux serveurs Web pour simplifier le déploiement du développement.

See all articles