How does Java implement inter-thread communication?

In Java, inter-thread communication can be achieved by:

1. Shared variables

Threads can communicate through shared variables. Multiple threads can read and write the same variable to exchange information. In this case, you need to ensure that thread access to shared variables is synchronized to avoid data races and inconsistent results.

The following is a sample code for thread communication using shared variables:

class Message {
    
    
    private String content;
    private boolean hasNewMessage = false;

    public synchronized void putMessage(String content) {
    
    
        while (hasNewMessage) {
    
    
            try {
    
    
                wait(); // 等待直到消息被消费
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        this.content = content;
        hasNewMessage = true;
        notifyAll(); // 唤醒等待的线程
    }

    public synchronized String getMessage() {
    
    
        while (!hasNewMessage) {
    
    
            try {
    
    
                wait(); // 等待直到有新消息
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        hasNewMessage = false;
        notifyAll(); // 唤醒等待的线程
        return content;
    }
}

class Producer implements Runnable {
    
    
    private Message message;

    public Producer(Message message) {
    
    
        this.message = message;
    }

    public void run() {
    
    
        String[] messages = {
    
     "Hello", "World", "Goodbye" };
        for (String msg : messages) {
    
    
            message.putMessage(msg);
            System.out.println("Producer: " + msg);
            try {
    
    
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        message.putMessage("Done");
    }
}

class Consumer implements Runnable {
    
    
    private Message message;

    public Consumer(Message message) {
    
    
        this.message = message;
    }

    public void run() {
    
    
        String msg = "";
        while (!msg.equals("Done")) {
    
    
            msg = message.getMessage();
            System.out.println("Consumer: " + msg);
        }
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Message message = new Message();
        Thread producerThread = new Thread(new Producer(message));
        Thread consumerThread = new Thread(new Consumer(message));

        producerThread.start();
        consumerThread.start();
    }
}

In this example, there is a Message class, which represents a message object. The putMessage method in the Message class is used to produce a message and store the message in the content variable. The getMessage method is used to consume messages and return the stored message content. Both methods use the synchronized keyword to achieve synchronization to ensure thread safety.

There is a Producer class which implements the Runnable interface for producing messages in one thread. The Consumer class also implements the Runnable interface for consuming messages in another thread.

In the main method of the Main class, a Message object is created, and a producer thread and a consumer thread are created. Start the two threads by calling the start method, and they will produce and consume messages concurrently.

In the console output, we will see that the producer thread and the consumer thread output messages alternately, and they communicate through the shared Message object.

2. Wait/notify mechanism

Java provides wait, notify and notifyAll methods for waiting and notification between threads. Threads can call the wait method to suspend their own execution until another thread calls the notify or notifyAll method on the same object to wake them up.

The following is a sample code for thread communication using wait/notify mechanism:

class Message {
    
    
    private String content;
    private boolean hasNewMessage = false;

    public synchronized void putMessage(String content) {
    
    
        while (hasNewMessage) {
    
    
            try {
    
    
                wait(); // 等待直到消息被消费
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        this.content = content;
        hasNewMessage = true;
        notifyAll(); // 唤醒等待的线程
    }

    public synchronized String getMessage() {
    
    
        while (!hasNewMessage) {
    
    
            try {
    
    
                wait(); // 等待直到有新消息
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        hasNewMessage = false;
        notifyAll(); // 唤醒等待的线程
        return content;
    }
}

class Producer implements Runnable {
    
    
    private Message message;

    public Producer(Message message) {
    
    
        this.message = message;
    }

    public void run() {
    
    
        String[] messages = {
    
     "Hello", "World", "Goodbye" };
        for (String msg : messages) {
    
    
            message.putMessage(msg);
            System.out.println("Producer: " + msg);
            try {
    
    
                Thread.sleep(1000); // 模拟耗时操作
            } catch (InterruptedException e) {
    
    
                Thread.currentThread().interrupt();
            }
        }
        message.putMessage("Done");
    }
}

class Consumer implements Runnable {
    
    
    private Message message;

    public Consumer(Message message) {
    
    
        this.message = message;
    }

    public void run() {
    
    
        String msg = "";
        while (!msg.equals("Done")) {
    
    
            msg = message.getMessage();
            System.out.println("Consumer: " + msg);
        }
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Message message = new Message();
        Thread producerThread = new Thread(new Producer(message));
        Thread consumerThread = new Thread(new Consumer(message));

        producerThread.start();
        consumerThread.start();
    }
}

The code in this example is the same as the previous example. The difference is that the putMessage and getMessage methods use the wait and notifyAll methods to wait and notify between threads. When the putMessage method calls wait, it releases the object's lock and waits to be woken up. When the getMessage method calls notifyAll, it wakes up the waiting thread and reacquires the object's lock.

In this way, the producer thread waits when there is no new message until the consumer thread consumes the message and calls the notifyAll method. Similarly, the consumer thread waits when there are no new messages until the producer thread generates a new message and calls the notifyAll method.

Whether it is a shared variable or a wait/notify mechanism, Java provides a variety of methods to achieve inter-thread communication. Choosing an appropriate method depends on the specific application scenario and requirements.

Guess you like

Origin blog.csdn.net/cz_00001/article/details/132693183