ホームページ  >  記事  >  Java  >  Java でのスレッド間通信とデータ共有の問題を解決する方法

Java でのスレッド間通信とデータ共有の問題を解決する方法

WBOY
WBOYオリジナル
2023-10-08 10:37:321418ブラウズ

Java でのスレッド間通信とデータ共有の問題を解決する方法

Java でのスレッド間通信とデータ共有の問題を解決する方法

Java では、スレッド間通信とデータ共有はマルチスレッドを実現するための重要な部分です。スレッドプログラミング。複数のスレッドが共有データに安全にアクセスし、効果的に通信するには、スレッド間の順序とデータの一貫性を確保する何らかのメカニズムを使用する必要があります。この記事では、Java での一般的なスレッド間通信およびデータ共有ソリューションをいくつか紹介し、対応するコード例を示します。

1. synchronized キーワードを使用してスレッド間通信とデータ共有を実装する

  1. synchronized メソッドを使用する

synchronized キーワードはメソッドを変更できますそのため、このメソッドを実行できるスレッドは 1 つだけであり、他のスレッドは待機する必要があります。これを使用して、スレッド間の通信とデータ共有を実装できます。

サンプル コード:

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

上記の例では、synchronized キーワードを使用して printNumbers() メソッドと printLetters() メソッドを変更することにより、スレッド A とスレッド B の間の順序と共有データは次のようになります。一貫性を確保しました。 flag flag を使用して 2 つのスレッドの交互実行を制御し、wait() メソッドとnotifyAll() メソッドを使用してスレッドの相互排他と通信を実行します。

  1. synchronized ブロックを使用する

synchronized キーワードを使用すると、1 つのスレッドだけが実行のためにコード ブロックに入ることができ、他のスレッドは待機する必要があるようにコード ブロックを変更することもできます。これを使用して、スレッド間の通信とデータ共有を実装できます。

サンプル コード:

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

上記の例では、synchronized キーワードを使用してコード ブロックを変更することで、スレッド A とスレッド B の間で順序と共有データの一貫性が確保されます。数値変数とロック オブジェクトを使用して 2 つのスレッドの交互実行を制御し、wait() メソッドとnotifyAll() メソッドを使用してスレッドの相互排他と通信を実行します。

2. Lock と Condition を使用してスレッド間通信とデータ共有を実現する

  1. ReentrantLock と Condition を使用する

ReentrantLock は Java Mutex によって提供されるリエントラントですロックを使用して、スレッド間の通信とデータ共有を実装できます。 Condition は ReentrantLock によって提供される条件オブジェクトであり、await() および signalAll() メソッドを通じてスレッドをブロックしたりウェイクアップしたりできます。

サンプルコード:

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

上記の例では、スレッド A とスレッド B 間の順序と共有データの一貫性は、ReentrantLock と Condition を使用して実現されます。数値変数、ロック オブジェクト、および Condition オブジェクトを使用して 2 つのスレッドの交互の実行を制御し、await() および signalAll() メソッドを通じてスレッドをブロックおよびウェイクアップします。

3. volatile キーワードを使用してスレッド間でのデータ共有を実現する

volatile キーワードを使用して変数を変更し、すべてのスレッドに対する変数の可視性を確保できます。 1 つのスレッドが揮発性変数の値を変更すると、他のスレッドはすぐに最新の値を参照するため、データの一貫性が確保されます。

サンプルコード:

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

上記の例では、volatile キーワードを使用してフラグ変数を変更することで、スレッド A とスレッド B の間の共有データの整合性が確保されます。 flag 変数を使用して 2 つのスレッドの交互実行を制御し、空のループを通じてフラグの値を待ちます。

概要:

この記事では、Java でのスレッド間通信とデータ共有の問題を解決するためのいくつかの一般的なソリューションを紹介します。これには、スレッド間通信を実装するための synchronized キーワードとロックと条件の使用が含まれます。 using volatile キーワードはデータ共有を実装します。上記のソリューションはすべて、複数のスレッド間の順序とデータの一貫性を保証できますが、どのソリューションを選択するかは、特定のニーズとシナリオによって異なります。実際のマルチスレッドプログラミングでは、プログラムの正確性とパフォーマンスを保証するために、スレッド間通信とデータ共有の問題を解決するために、特定の状況に応じて適切な解決策を選択する必要があります。

以上がJava でのスレッド間通信とデータ共有の問題を解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。