线程之间的通信是指多个线程协同工作,通过共享的资源或通过某种同步机制进行信息交换或协调。在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等高级并发工具可以让我们更加方便地处理复杂的线程间通信场景。
本文暂时没有评论,来添加一个吧(●'◡'●)