JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

大厂面试-Java如何实现线程之间的通信?

wys521 2025-02-20 18:25:26 精选教程 30 ℃ 0 评论

线程之间的通信是指多个线程协同工作,通过共享的资源或通过某种同步机制进行信息交换或协调。在Java中提供了多种机制来实现线程之间的通信,我们可以通过wait()、notify()和notifyAll()方法;可以通过volatile关键字;还可以通过join()方法或者通过BlockingQueue来实现线程通信操作。下面我们就来详细的介绍在Java中线程之间通信的机制。

使用wait()和notify()进行线程通信

在Java中,我们调用wait()方法线程会释放锁,从而进入到等待状态,直到其他线程调用notify()或notifyAll()来唤醒它,如下所示。

class SharedResource {
    private boolean ready = false;

    // 线程等待,直到资源准备好
    public synchronized void waitForReady() {
        while (!ready) {
            try {
                System.out.println(Thread.currentThread().getName() + " waiting for ready state...");
                wait();  // 当前线程等待,释放锁
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println(Thread.currentThread().getName() + " resuming execution...");
    }

    // 通知其他线程资源已准备好
    public synchronized void setReady() {
        ready = true;
        System.out.println(Thread.currentThread().getName() + " setting resource to ready...");
        notify();  // 唤醒一个正在等待的线程
    }
}

public class WaitNotifyExample {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();

        Thread waitingThread = new Thread(() -> {
            resource.waitForReady();
            System.out.println(Thread.currentThread().getName() + " finished execution.");
        }, "WaitingThread");

        Thread notifyingThread = new Thread(() -> {
            try {
                Thread.sleep(2000);  // 模拟资源准备的时间
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            resource.setReady();
        }, "NotifyingThread");

        waitingThread.start();
        notifyingThread.start();
    }
}

输出结果如下所示。

WaitingThread waiting for ready state...
NotifyingThread setting resource to ready...
WaitingThread resuming execution...
WaitingThread finished execution.

从输出结果,我们可以看出,在执行线程的时候进入到了等待状态,然后等待所有的资源准备好了之后,在开始执行线程中正常的操作。

使用volatile进行线程通信

volatile关键字确保变量在多个线程之间的可见性,也就是说线程对变量的修改会立即对其他线程可见,从而保证了变量的信息在多个线程操作之间是共享的,如下所示。

class VolatileExample {
    private volatile boolean running = true;

    public void startTask() {
        Thread taskThread = new Thread(() -> {
            while (running) {
                System.out.println(Thread.currentThread().getName() + " is running...");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(Thread.currentThread().getName() + " has stopped.");
        });

        taskThread.start();
    }

    public void stopTask() {
        running = false;
    }

    public static void main(String[] args) {
        VolatileExample example = new VolatileExample();
        example.startTask();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        System.out.println("Main thread stopping the task...");
        example.stopTask();
    }
}

输出结果如下所示

Thread-0 is running...
Thread-0 is running...
Thread-0 is running...
Thread-0 is running...
Main thread stopping the task...
Thread-0 has stopped.

使用 join() 进行线程通信

在Java中,join()方法可以让一个线程等待另一个线程的结束,可以用来实现线程之间的简单同步。如下所示

public class JoinExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            try {
                Thread.sleep(3000);  // 模拟工作
                System.out.println(Thread.currentThread().getName() + " finished work.");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Thread-1");

        Thread thread2 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " waiting for Thread-1 to finish...");
            try {
                thread1.join();  // 等待thread1完成
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            System.out.println(Thread.currentThread().getName() + " resuming work after Thread-1.");
        }, "Thread-2");

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

输出结果如下所示。

Thread-2 waiting for Thread-1 to finish...
Thread-1 finished work.
Thread-2 resuming work after Thread-1.

使用BlockingQueue进行线程通信

在生产者-消费者模型中,我们可以通过BlockingQueue线程安全队列来实现多线程之间的通信,BlockingQueue的put()方法会阻塞直到队列有空间,而take()方法会阻塞直到队列有元素。通过这种方式,我们就可以实现多个线程的之间的信息共享,如下所示。

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

class Producer implements Runnable {
    private BlockingQueue queue;

    public Producer(BlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            try {
                System.out.println("Producer produced: " + i);
                queue.put(i);  // 阻塞直到队列有空间
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

class Consumer implements Runnable {
    private BlockingQueue queue;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                Integer item = queue.take();  // 阻塞直到队列有元素
                System.out.println("Consumer consumed: " + item);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

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

        Thread producerThread = new Thread(new Producer(queue));
        Thread consumerThread = new Thread(new Consumer(queue));

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

结果如下所示。

Producer produced: 1
Consumer consumed: 1
Producer produced: 2
Consumer consumed: 2
Producer produced: 3
Consumer consumed: 3
Producer produced: 4
Consumer consumed: 4
Producer produced: 5
Consumer consumed: 5

从输出结果来看,这种方式生产者和消费者都是按照顺序进行生产消费的。所以保证了两个线程之间操作的信息共享。

总结

Java中有多种方式来实现线程之间的通信,选择哪种方式取决于具体的应用场景。wait()和notify()是最常用的方式,但使用时需要特别注意避免死锁等问题。而BlockingQueue等高级并发工具可以让我们更加方便地处理复杂的线程间通信场景。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表