Maison > Java > javaDidacticiel > le corps du texte

Deux façons de coopérer entre les threads dans la concurrence Java : attendre, notifier, notifierAll et Condition

黄舟
Libérer: 2017-03-18 10:09:08
original
1251 Les gens l'ont consulté

Coopération entre les fils. Par exemple, le modèle producteur-consommateur le plus classique : lorsque la file d'attente est pleine, le producteur doit attendre que la file d'attente ait de la place avant de pouvoir continuer à y mettre des marchandises. Pendant la période d'attente, le producteur doit libérer des ressources critiques (. c'est-à-dire la file d'attente) droit d'occupation. Parce que si le producteur ne libère pas le droit d'occuper des ressources critiques, alors le consommateur ne pourra pas consommer les biens dans la file d'attente, il n'y aura pas de place dans la file d'attente et le producteur attendra indéfiniment. Par conséquent, dans des circonstances normales, lorsque la file d'attente est pleine, il sera demandé au producteur de céder le droit d'occuper des ressources critiques et d'entrer dans un état suspendu. Attendez ensuite que le consommateur consomme les biens, puis le consommateur informe le producteur qu'il y a de la place dans la file d'attente. De même, lorsque la file d'attente est vide, le consommateur doit attendre que le producteur lui signale qu'il y a un élément dans la file d'attente. Ce processus de communication mutuelle est la coopération entre les fils.

wait(), notify() et notifyAll()

[code]/**
 * Wakes up a single thread that is waiting on this object's
 * monitor. If any threads are waiting on this object, one of them
 * is chosen to be awakened. The choice is arbitrary and occurs at
 * the discretion of the implementation. A thread waits on an object's
 * monitor by calling one of the wait methods
 */
public final native void notify();

/**
 * Wakes up all threads that are waiting on this object's monitor. A
 * thread waits on an object's monitor by calling one of the
 * wait methods.
 */
public final native void notifyAll();

/**
 * Causes the current thread to wait until either another thread invokes the
 * {@link java.lang.Object#notify()} method or the
 * {@link java.lang.Object#notifyAll()} method for this object, or a
 * specified amount of time has elapsed.
 * <p>
 * The current thread must own this object&#39;s monitor.
 */
public final native void wait(long timeout) throws InterruptedException;
Copier après la connexion

1) wait(), notify() et notifyAll( ) est une méthode locale, définitive et ne peut pas être remplacée.
2) L'appel de la méthode wait() d'un objet peut bloquer le thread actuel, et le thread actuel doit posséder le moniteur (c'est-à-dire le verrou) de cet objet
3) L'appel de la méthode notify() d'un objet peut réveiller un objet Le thread qui attend le moniteur de cet objet. S'il y a plusieurs threads qui attendent le moniteur de cet objet, un seul d'entre eux peut être réveillé
4) L'appel de la méthode notifyAll() peut se réveiller ; tous les moniteurs qui attendent cet objet. Thread;
Certains amis peuvent se poser des questions : pourquoi ces trois ne sont pas des méthodes déclarées dans la classe Thread, mais des méthodes déclarées dans la classe Object (bien sûr, puisque la classe Thread hérite). la classe Object, Thread peut également appeler trois méthodes) ? En fait, ce problème est très simple. Puisque chaque objet a un moniteur (c'est-à-dire un verrou), si le thread actuel doit attendre le verrouillage d'un objet, il doit bien sûr être opéré via cet objet. Au lieu d'utiliser le thread actuel pour fonctionner, étant donné que le thread actuel peut attendre des verrous de plusieurs threads, il serait très compliqué d'opérer via les threads.
Comme mentionné ci-dessus, si la méthode wait() d'un objet est appelée, le thread actuel doit posséder le moniteur (c'est-à-dire le verrou) de cet objet, donc l'appel de la méthode wait() doit être effectué dans un bloc synchronisé ou synchronisé méthode (bloc synchronisé ou méthode synchronisée).
Appeler la méthode wait() d'un objet équivaut à demander au thread courant de remettre le moniteur de cet objet, puis d'entrer dans l'état d'attente, en attendant à nouveau l'acquisition ultérieure du verrou de cet objet (le sleep dans la classe Thread oblige le thread actuel à suspendre l'exécution pendant un certain temps, donnant ainsi aux autres threads une chance de continuer à s'exécuter, mais il ne libère pas le verrou de l'objet
La méthode notify() peut réveiller un); thread qui attend le moniteur de l'objet, lorsque plusieurs threads attendent l'objet. Si le moniteur est utilisé, un seul des threads peut être réveillé et le thread spécifique à réveiller est inconnu.
De même, lors de l'appel de la méthode notify() d'un objet, le thread courant doit également posséder le moniteur de cet objet, donc l'appel de la méthode notify() doit se faire dans un bloc synchronisé ou une méthode synchronisée (bloc synchronisé ou synchronisé méthode).
La méthode nofityAll() peut réveiller tous les threads en attente du moniteur de l'objet, ce qui est différent de la méthode notify().
Quelque chose à noter ici : les méthodes notify() et notifyAll() réveillent uniquement le thread en attente du moniteur de l'objet, et ne déterminent pas quel thread peut obtenir le moniteur.
Donnez un exemple simple : supposons qu'il y ait trois threads Thread1, Thread2 et Thread3 qui attendent tous le moniteur de l'objet objectA. À ce moment, Thread4 possède le moniteur de l'objet objectA après l'appel de la méthode objectA.notify(). Thread4, Thread1, un seul des Thread2 et Thread3 peut être réveillé. Notez qu'être réveillé ne signifie pas que le moniteur de l'objetA est obtenu immédiatement. Si la méthode objectA.notifyAll() est appelée dans Thread4, les trois threads Thread1, Thread2 et Thread3 seront réveillés. Le thread qui pourra ensuite obtenir le moniteur de l'objetA dépend de la planification du système d'exploitation.
Portez une attention particulière à ce qui précède. Être réveillé par un thread ne signifie pas qu'il obtient immédiatement le moniteur de l'objet. Ce n'est qu'après avoir appelé notify() ou notifyAll() et quitté le bloc synchronisé et libéré le verrouillage de l'objet que d'autres peuvent l'être. les threads obtiennent le verrou pour l'exécution.

[code]public class Test {
    public static Object object = new Object();
    public static void main(String[] args) {
        Thread1 thread1 = new Thread1();
        Thread2 thread2 = new Thread2();

        thread1.start();

        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        thread2.start();
    }

    static class Thread1 extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                try {
                    object.wait();
                } catch (InterruptedException e) {
                }
                System.out.println("线程"+Thread.currentThread().getName()+"获取到了锁");
            }
        }
    }

    static class Thread2 extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                object.notify();
                System.out.println("线程"+Thread.currentThread().getName()+"调用了object.notify()");
            }
            System.out.println("线程"+Thread.currentThread().getName()+"释放了锁");
        }
    }
}
Copier après la connexion

Condition

La condition n'est apparue que dans Java 1.5. Elle est utilisée pour remplacer wait(), notify() de l'objet traditionnel. implémente la collaboration entre les threads. Par rapport à l'utilisation de wait() et notify() d'Object, il est plus sûr et plus efficace d'utiliser wait() et signal() de Condition1 pour réaliser une collaboration inter-thread. Par conséquent, il est généralement recommandé d'utiliser Condition
Condition est une interface, et les méthodes de base sont les méthodes wait() et signal()
Condition dépend de l'interface Lock, et le code de base pour générer une Condition est ; lock.newCondition()
Les méthodes wait() et signal() de Calling Condition doivent être protégées par un verrou, ce qui signifie qu'elles doivent être utilisées entre lock.lock() et lock.unlock

.
Conditon中的await()对应Object的wait();
  Condition中的signal()对应Object的notify();
  Condition中的signalAll()对应Object的notifyAll()。
Copier après la connexion
[code]public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);

    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();

        producer.start();
        consumer.start();
    }

    class Consumer extends Thread{

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

        private void consume() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.poll();          //每次移走队首元素
                    queue.notify();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                }
            }
        }
    }

    class Producer extends Thread{

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

        private void produce() {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    queue.notify();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                }
            }
        }
    }
}
Copier après la connexion
[code]public class Test {
    private int queueSize = 10;
    private PriorityQueue<Integer> queue = new PriorityQueue<Integer>(queueSize);
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();

        producer.start();
        consumer.start();
    }

    class Consumer extends Thread{

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

        private void consume() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == 0){
                        try {
                            System.out.println("队列空,等待数据");
                            notEmpty.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.poll();                //每次移走队首元素
                    notFull.signal();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                } finally{
                    lock.unlock();
                }
            }
        }
    }

    class Producer extends Thread{

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

        private void produce() {
            while(true){
                lock.lock();
                try {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满,等待有空余空间");
                            notFull.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    queue.offer(1);        //每次插入一个元素
                    notEmpty.signal();
                    System.out.println("向队列取中插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                } finally{
                    lock.unlock();
                }
            }
        }
    }
}
Copier après la connexion

以上就是java-并发-线程间协作的两种方式:wait、notify、notifyAll和Condition的内容,更多相关内容请关注PHP中文网(www.php.cn)!

相关文章:

java notify和notifyAll的对比详细介绍

wait, notify 和 notifyAll的正确用法

通过实例讨论notify()和notifyAll()的本质区别

É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
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!