Maison  >  Article  >  Java  >  Comment résoudre les problèmes de communication inter-thread et de partage de données en Java

Comment résoudre les problèmes de communication inter-thread et de partage de données en Java

WBOY
WBOYoriginal
2023-10-08 10:37:321381parcourir

Comment résoudre les problèmes de communication inter-thread et de partage de données en Java

Comment résoudre le problème de la communication inter-thread et du partage de données en Java

En Java, la communication inter-thread et le partage de données sont des composants importants pour réaliser une programmation multi-thread. Pour que plusieurs threads puissent accéder en toute sécurité aux données partagées et communiquer efficacement, nous devons utiliser un mécanisme pour garantir l'ordre et la cohérence des données entre les threads. Cet article présentera plusieurs solutions courantes de communication inter-thread et de partage de données en Java et fournira des exemples de code correspondants.

1. Utilisez le mot-clé synchronisé pour implémenter la communication entre les threads et le partage de données

  1. Utilisez la méthode synchronisée

Le mot-clé synchronisé peut modifier la méthode afin qu'un seul thread puisse entrer dans la méthode pour l'exécution et que d'autres threads en aient besoin attendre. Cela peut être utilisé pour implémenter la communication et le partage de données entre les threads.

Exemple de code :

public class ThreadCommunication {
    private boolean flag = false;

    public synchronized void printNumbers() {
        // 线程A负责打印奇数
        for (int i = 1; i <= 10; i += 2) {
            while (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("ThreadA: " + i);
            flag = true;
            notifyAll();
        }
    }

    public synchronized void printLetters() {
        // 线程B负责打印偶数
        for (char c = 'A'; c <= 'J'; c += 2) {
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("ThreadB: " + c);
            flag = false;
            notifyAll();
        }
    }

    public static void main(String[] args) {
        final ThreadCommunication communication = new ThreadCommunication();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printNumbers();
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printLetters();
            }
        });

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

Dans l'exemple ci-dessus, en modifiant les méthodes printNumbers() et printLetters() avec le mot-clé synchronisé, la cohérence de la commande et des données partagées entre le thread A et le thread B est assurée. Utilisez l'indicateur flag pour contrôler l'exécution alternative de deux threads et utilisez les méthodes wait() et notifyAll() pour effectuer l'exclusion mutuelle et la communication des threads.

  1. Utilisation de blocs synchronisés

Le mot-clé synchronisé peut également modifier le bloc de code afin qu'un seul thread puisse entrer dans le bloc de code pour l'exécution et que les autres threads doivent attendre. Cela peut être utilisé pour implémenter la communication et le partage de données entre les threads.

Exemple de code :

public class ThreadCommunication2 {
    private Object lock = new Object();
    private int number = 0;

    public void printNumbers() {
        synchronized (lock) {
            // 线程A负责打印奇数
            for (int i = 1; i <= 10; i += 2) {
                while (number % 2 == 0) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("ThreadA: " + i);
                number++;
                lock.notifyAll();
            }
        }
    }

    public void printLetters() {
        synchronized (lock) {
            // 线程B负责打印偶数
            for (char c = 'A'; c <= 'J'; c += 2) {
                while (number % 2 != 0) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("ThreadB: " + c);
                number++;
                lock.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        final ThreadCommunication2 communication = new ThreadCommunication2();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printNumbers();
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printLetters();
            }
        });

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

Dans l'exemple ci-dessus, en décorant le bloc de code avec le mot-clé synchronisé, la cohérence de l'ordre et des données partagées entre le thread A et le thread B est assurée. Utilisez des variables numériques et des objets de verrouillage pour contrôler l'exécution alternative de deux threads, et utilisez les méthodes wait() et notifyAll() pour effectuer l'exclusion mutuelle et la communication des threads.

2. Utilisez Lock et Condition pour réaliser la communication entre les threads et le partage de données

  1. Utilisez ReentrantLock et Condition

ReentrantLock est un verrou mutex réentrant fourni par Java, qui peut être utilisé pour réaliser la communication entre les threads et le partage de données. . Condition est un objet de condition fourni par ReentrantLock, qui peut bloquer et réveiller les threads via ses méthodes wait() et signalAll().

Exemple de code :

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadCommunication3 {
    private Lock lock = new ReentrantLock();
    private Condition numberCondition = lock.newCondition();
    private Condition letterCondition = lock.newCondition();
    private int number = 0;

    public void printNumbers() {
        lock.lock();
        try {
            // 线程A负责打印奇数
            for (int i = 1; i <= 10; i += 2) {
                while (number % 2 == 0) {
                    try {
                        numberCondition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("ThreadA: " + i);
                number++;
                letterCondition.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }

    public void printLetters() {
        lock.lock();
        try {
            // 线程B负责打印偶数
            for (char c = 'A'; c <= 'J'; c += 2) {
                while (number % 2 != 0) {
                    try {
                        letterCondition.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("ThreadB: " + c);
                number++;
                numberCondition.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        final ThreadCommunication3 communication = new ThreadCommunication3();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printNumbers();
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printLetters();
            }
        });

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

Dans l'exemple ci-dessus, la cohérence de la commande et des données partagées entre le thread A et le thread B est obtenue en utilisant ReentrantLock et Condition. Utilisez des variables numériques, des objets de verrouillage et des objets Condition pour contrôler l'exécution alternative de deux threads, et bloquez et réveillez les threads via les méthodes wait() et signalAll().

3. Utilisez le mot-clé volatile pour partager des données entre les threads

Le mot-clé volatile peut être utilisé pour modifier les variables afin d'assurer la visibilité des variables sur tous les threads. Lorsqu'un thread modifie la valeur d'une variable volatile, les autres threads verront immédiatement la dernière valeur, garantissant ainsi la cohérence des données.

Exemple de code :

public class ThreadCommunication4 {
    private volatile boolean flag = false;

    public void printNumbers() {
        // 线程A负责打印奇数
        for (int i = 1; i <= 10; i += 2) {
            while (flag) {
                // 空循环,等待flag为false
            }
            System.out.println("ThreadA: " + i);
            flag = true;
        }
    }

    public void printLetters() {
        // 线程B负责打印偶数
        for (char c = 'A'; c <= 'J'; c += 2) {
            while (!flag) {
                // 空循环,等待flag为true
            }
            System.out.println("ThreadB: " + c);
            flag = false;
        }
    }

    public static void main(String[] args) {
        final ThreadCommunication4 communication = new ThreadCommunication4();

        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printNumbers();
            }
        });

        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                communication.printLetters();
            }
        });

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

Dans l'exemple ci-dessus, en utilisant le mot-clé volatile pour modifier la variable flag, la cohérence des données partagées entre le thread A et le thread B est obtenue. Utilisez la variable flag pour contrôler l'exécution alternative des deux threads et attendez la valeur du flag dans une boucle vide.

Résumé :

Cet article présente plusieurs solutions courantes aux problèmes de communication inter-thread et de partage de données en Java, notamment l'utilisation du mot-clé synchronisé et du verrouillage et de la condition pour réaliser une communication inter-thread, et l'utilisation du mot-clé volatile pour réaliser le partage de données. Toutes les solutions ci-dessus peuvent garantir la cohérence de l'ordre et des données entre plusieurs threads. La solution à choisir dépend des besoins et des scénarios spécifiques. Dans la programmation multithread réelle, il est nécessaire de choisir une solution appropriée en fonction de la situation spécifique pour résoudre le problème de la communication inter-thread et du partage de données, afin de garantir l'exactitude et les performances du programme.

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!

Déclaration:
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