Backend Development 10 min read

Java Thread Communication Methods: Synchronized, Polling, wait/notify, and Piped Streams

This article explains four common Java thread communication techniques—synchronized blocks, while‑polling, wait/notify, and piped streams—providing code examples and discussing their advantages, drawbacks, and practical usage in multithreaded applications.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Java Thread Communication Methods: Synchronized, Polling, wait/notify, and Piped Streams

In daily development, multithreading and concurrency are not often used by some developers, but they are frequent interview topics; therefore this article collects typical Java thread communication methods for reference.

1. Introduction

This article summarizes the author's understanding of Java thread communication, using code examples extracted from books.

2. Thread Communication Methods

① Synchronized

Synchronization uses the synchronized keyword to achieve communication between threads that share the same object.

Example:

public class MyObject {
    synchronized public void methodA() {
        // do something....
    }
    synchronized public void methodB() {
        // do some other thing
    }
}

public class ThreadA extends Thread {
    private MyObject object;
    // constructor omitted
    @Override
    public void run() {
        super.run();
        object.methodA();
    }
}

public class ThreadB extends Thread {
    private MyObject object;
    // constructor omitted
    @Override
    public void run() {
        super.run();
        object.methodB();
    }
}

public class Run {
    public static void main(String[] args) {
        MyObject object = new MyObject();
        // Thread A and Thread B hold the same object
        ThreadA a = new ThreadA(object);
        ThreadB b = new ThreadB(object);
        a.start();
        b.start();
    }
}

Because Thread A and Thread B hold the same MyObject instance, Thread B must wait for Thread A to finish methodA() before it can execute methodB() , thus achieving communication via shared memory.

② While Polling

Code example:

import java.util.ArrayList;
import java.util.List;

public class MyList {
    private List
list = new ArrayList
();
    public void add() {
        list.add("elements");
    }
    public int size() {
        return list.size();
    }
}

public class ThreadA extends Thread {
    private MyList list;
    public ThreadA(MyList list) {
        super();
        this.list = list;
    }
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10; i++) {
                list.add();
                System.out.println("Added " + (i + 1) + " elements");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadB extends Thread {
    private MyList list;
    public ThreadB(MyList list) {
        super();
        this.list = list;
    }
    @Override
    public void run() {
        try {
            while (true) {
                if (list.size() == 5) {
                    System.out.println("==5, thread B will exit");
                    throw new InterruptedException();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        MyList service = new MyList();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

Thread A continuously changes a condition, while Thread B repeatedly checks the condition ( list.size()==5 ) in a while loop, achieving communication but wasting CPU resources because the polling thread does no useful work.

Additionally, visibility problems can arise due to memory visibility; if Thread B reads a locally cached variable, it may not see updates made by Thread A, potentially causing a dead loop.

③ wait/notify Mechanism

Code example:

import java.util.ArrayList;
import java.util.List;

public class MyList {
    private static List
list = new ArrayList
();
    public static void add() {
        list.add("anyString");
    }
    public static int size() {
        return list.size();
    }
}

public class ThreadA extends Thread {
    private Object lock;
    public ThreadA(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        try {
            synchronized (lock) {
                if (MyList.size() != 5) {
                    System.out.println("wait begin " + System.currentTimeMillis());
                    lock.wait();
                    System.out.println("wait end " + System.currentTimeMillis());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadB extends Thread {
    private Object lock;
    public ThreadB(Object lock) {
        super();
        this.lock = lock;
    }
    @Override
    public void run() {
        try {
            synchronized (lock) {
                for (int i = 0; i < 10; i++) {
                    MyList.add();
                    if (MyList.size() == 5) {
                        lock.notify();
                        System.out.println("Notification sent");
                    }
                    System.out.println("Added " + (i + 1) + " elements!");
                    Thread.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Run {
    public static void main(String[] args) {
        try {
            Object lock = new Object();
            ThreadA a = new ThreadA(lock);
            a.start();
            Thread.sleep(50);
            ThreadB b = new ThreadB(lock);
            b.start();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Thread A calls wait() when the condition ( list.size()!=5 ) is not met, releasing the CPU and entering a blocked state; Thread B adds elements and calls notify() when the condition becomes true, waking Thread A. This improves CPU utilization but can fail if the notification is sent before Thread A begins waiting.

④ Piped Communication

This method uses java.io.PipedInputStream and java.io.PipedOutputStream to transfer data between threads, resembling a message‑passing mechanism rather than shared memory.

In distributed systems, the two main communication mechanisms are shared‑memory and message‑based communication. The synchronized keyword and while‑polling belong to shared‑memory communication, while piped streams belong to message‑based communication.

Source: cnblogs.com/hapjin/p/5492619.html

JavaSynchronizationMultithreadingThread Communicationpollingwait-notifyPiped Streams
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.