Home  >  Article  >  Java  >  How to solve inter-thread communication and data sharing issues in Java

How to solve inter-thread communication and data sharing issues in Java

WBOY
WBOYOriginal
2023-10-08 10:37:321383browse

How to solve inter-thread communication and data sharing issues in Java

How to solve the problem of inter-thread communication and data sharing in Java

In Java, inter-thread communication and data sharing are important parts of realizing multi-threaded programming. In order for multiple threads to safely access shared data and communicate effectively, we need to use some mechanism to ensure the order and data consistency between threads. This article will introduce several common inter-thread communication and data sharing solutions in Java and provide corresponding code examples.

1. Use the synchronized keyword to implement inter-thread communication and data sharing

  1. Use the synchronized method

The synchronized keyword can modify the method so that there is only one Threads can enter this method for execution, and other threads need to wait. This can be used to implement communication and data sharing between threads.

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

In the above example, by using the synchronized keyword to modify the printNumbers() and printLetters() methods, the order and shared data between thread A and thread B are ensured consistency. Use the flag flag to control the alternate execution of two threads, and use the wait() and notifyAll() methods to perform thread mutual exclusion and communication.

  1. Use synchronized block

The synchronized keyword can also modify the code block so that only one thread can enter the code block for execution, and other threads need to wait. This can be used to implement communication and data sharing between threads.

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

In the above example, by using the synchronized keyword to modify the code block, the consistency of the order and shared data between thread A and thread B is ensured. Use number variables and lock objects to control the alternate execution of two threads, and use the wait() and notifyAll() methods to perform thread mutual exclusion and communication.

2. Use Lock and Condition to realize inter-thread communication and data sharing

  1. Use ReentrantLock and Condition

ReentrantLock is reentrant provided by Java Mutex locks can be used to implement communication and data sharing between threads. Condition is a condition object provided by ReentrantLock, which can block and wake up threads through its await() and signalAll() methods.

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

In the above example, the consistency of the order and shared data between thread A and thread B is achieved by using ReentrantLock and Condition. Use number variables, lock objects, and Condition objects to control the alternate execution of two threads, and block and wake up threads through the await() and signalAll() methods.

3. Use volatile keyword to realize data sharing between threads

The volatile keyword can be used to modify variables to ensure the visibility of variables to all threads. When one thread modifies the value of a volatile variable, other threads will immediately see the latest value, thus ensuring data consistency.

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

In the above example, by using the volatile keyword to modify the flag variable, the consistency of the shared data between thread A and thread B is achieved. Use the flag variable to control the alternate execution of the two threads, and wait for the value of the flag through an empty loop.

Summary:

This article introduces several common solutions to solve inter-thread communication and data sharing problems in Java, including using the synchronized keyword and Lock and Condition to implement inter-thread communication, and using The volatile keyword implements data sharing. All of the above solutions can ensure the order and data consistency between multiple threads. Which solution to choose depends on the specific needs and scenarios. In actual multi-thread programming, it is necessary to choose an appropriate solution according to the specific situation to solve the problem of inter-thread communication and data sharing, so as to ensure the correctness and performance of the program.

The above is the detailed content of How to solve inter-thread communication and data sharing issues in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn