面试题:Java 中线程之间如何进行通信?

在 Java 中,线程之间的通信是实现多线程协作的重要手段。线程通信的主要目的是让多个线程能够协调工作,共享数据或通知彼此状态的变化。Java 提供了多种机制来实现线程之间的通信,主要包括以下几种方式:


1. 共享变量

线程可以通过共享变量进行通信,但需要确保对共享变量的访问是线程安全的。常用的方法包括:

  • volatile 关键字:确保变量的可见性。
  • synchronized 关键字:确保对共享变量的访问是原子的。
  • 原子类:如 AtomicIntegerAtomicLong 等,提供原子操作。

示例:

public class SharedVariableExample {
    private volatile boolean flag = false;

    public void setFlag() {
        flag = true;
    }

    public void waitForFlag() {
        while (!flag) {
            // 等待 flag 变为 true
        }
        System.out.println("Flag is true!");
    }

    public static void main(String[] args) {
        SharedVariableExample example = new SharedVariableExample();

        Thread thread1 = new Thread(example::waitForFlag);
        Thread thread2 = new Thread(example::setFlag);

        thread1.start();
        thread2.start();
    }
}

2. wait() 和 notify() / notifyAll()

wait()notify() 和 notifyAll() 是 Object 类的方法,用于实现线程之间的等待和通知机制。这些方法必须在 synchronized 代码块或方法中使用。

  • wait():使当前线程进入等待状态,并释放锁。
  • notify():唤醒一个等待的线程。
  • notifyAll():唤醒所有等待的线程。

示例:

public class WaitNotifyExample {
    private final Object lock = new Object();
    private boolean isReady = false;

    public void waitForReady() throws InterruptedException {
        synchronized (lock) {
            while (!isReady) {
                lock.wait(); // 等待通知
            }
            System.out.println("Ready!");
        }
    }

    public void setReady() {
        synchronized (lock) {
            isReady = true;
            lock.notifyAll(); // 通知所有等待的线程
        }
    }

    public static void main(String[] args) {
        WaitNotifyExample example = new WaitNotifyExample();

        Thread thread1 = new Thread(() -> {
            try {
                example.waitForReady();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(example::setReady);

        thread1.start();
        thread2.start();
    }
}

3. BlockingQueue

BlockingQueue 是 java.util.concurrent 包中的一个接口,提供了线程安全的队列操作。它支持阻塞的插入和移除操作,常用于生产者-消费者模型。

示例:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class BlockingQueueExample {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();

        // 生产者线程
        Thread producer = new Thread(() -> {
            try {
                queue.put("Message");
                System.out.println("Produced: Message");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 消费者线程
        Thread consumer = new Thread(() -> {
            try {
                String message = queue.take();
                System.out.println("Consumed: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.start();
        consumer.start();
    }
}

4. CountDownLatch

CountDownLatch 是 java.util.concurrent 包中的一个同步工具,用于让一个或多个线程等待其他线程完成操作。

示例:

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(2);

        Thread thread1 = new Thread(() -> {
            System.out.println("Thread 1 is running");
            latch.countDown();
        });

        Thread thread2 = new Thread(() -> {
            System.out.println("Thread 2 is running");
            latch.countDown();
        });

        thread1.start();
        thread2.start();

        latch.await(); // 等待两个线程完成
        System.out.println("All threads have finished!");
    }
}

5. CyclicBarrier

CyclicBarrier 是 java.util.concurrent 包中的一个同步工具,用于让一组线程互相等待,直到所有线程都到达某个屏障点。

示例:

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(2, () -> {
            System.out.println("All threads have reached the barrier!");
        });

        Thread thread1 = new Thread(() -> {
            try {
                System.out.println("Thread 1 is running");
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                System.out.println("Thread 2 is running");
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
    }
}

6. Exchanger

Exchanger 是 java.util.concurrent 包中的一个同步工具,用于在两个线程之间交换数据。

示例:

import java.util.concurrent.Exchanger;

public class ExchangerExample {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();

        Thread thread1 = new Thread(() -> {
            try {
                String message = exchanger.exchange("Message from Thread 1");
                System.out.println("Thread 1 received: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                String message = exchanger.exchange("Message from Thread 2");
                System.out.println("Thread 2 received: " + message);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
    }
}

总结

Java 提供了多种线程通信机制,包括共享变量、wait()/notify()BlockingQueueCountDownLatchCyclicBarrier 和 Exchanger 等。选择合适的机制取决于具体的应用场景和需求。

THE END
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容