Java中线程之间是如何通信的

Java中线程之间是如何通信的

在 Java 中,线程之间的通信是通过共享内存模型来实现的,线程通过共享的对象和变量来交换数据。为了确保线程间通信的正确性,Java 提供了一系列机制来实现线程安全、同步和通信。以下是常用的几种线程间通信的方式,以及它们的使用方法和场景。

1. 共享变量与同步机制

多个线程可以通过共享对象的变量进行通信,但为了避免数据不一致的问题,必须使用同步机制来控制对共享变量的访问。

使用 synchronized 关键字: synchronized 确保在同一时刻只有一个线程可以执行同步代码块。它可以同步方法或代码块,用于保护共享数据。

示例:

class Counter {

private int count = 0;

public synchronized void increment() {

count++;

}

public synchronized int getCount() {

return count;

}

}

public class SyncExample {

public static void main(String[] args) {

Counter counter = new Counter();

Thread t1 = new Thread(() -> {

for (int i = 0; i < 1000; i++) {

counter.increment();

}

});

Thread t2 = new Thread(() -> {

for (int i = 0; i < 1000; i++) {

counter.increment();

}

});

t1.start();

t2.start();

try {

t1.join();

t2.join();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("Final count: " + counter.getCount());

}

}

使用场景:用于保护共享资源,防止多个线程同时读写导致数据不一致的问题。

使用 volatile 关键字: volatile 确保一个线程对变量的修改对其他线程立即可见。它适用于轻量级的变量同步,通常用于标志位控制。

示例:

class Flag {

private volatile boolean running = true;

public void stop() {

running = false;

}

public boolean isRunning() {

return running;

}

}

public class VolatileExample {

public static void main(String[] args) {

Flag flag = new Flag();

Thread t1 = new Thread(() -> {

while (flag.isRunning()) {

System.out.println("Thread is running");

}

System.out.println("Thread stopped");

});

t1.start();

try {

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

}

flag.stop();

}

}

使用场景:用于控制线程的退出、开关操作等轻量级场景。

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

Object 类的这三个方法用于在同步块内实现线程间的协作。线程可以通过 wait() 进入等待状态,直到另一个线程调用 notify() 或 notifyAll() 唤醒它们。

wait():当前线程进入等待状态,并释放锁。notify():唤醒一个正在等待同一锁的线程。notifyAll():唤醒所有等待同一锁的线程。示例:生产者-消费者模型

class SharedResource {

private int value;

private boolean hasValue = false;

public synchronized void produce(int newValue) throws InterruptedException {

while (hasValue) {

wait(); // 等待消费者消费

}

value = newValue;

hasValue = true;

System.out.println("Produced: " + value);

notify(); // 唤醒消费者

}

public synchronized void consume() throws InterruptedException {

while (!hasValue) {

wait(); // 等待生产者生产

}

System.out.println("Consumed: " + value);

hasValue = false;

notify(); // 唤醒生产者

}

}

public class ProducerConsumerExample {

public static void main(String[] args) {

SharedResource resource = new SharedResource();

Thread producer = new Thread(() -> {

try {

for (int i = 0; i < 5; i++) {

resource.produce(i);

Thread.sleep(100);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

});

Thread consumer = new Thread(() -> {

try {

for (int i = 0; i < 5; i++) {

resource.consume();

Thread.sleep(200);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

});

producer.start();

consumer.start();

}

}

使用场景:适用于线程间的协调工作,比如生产者-消费者模型,一个线程负责生产资源,另一个线程负责消费资源。

3. Lock 和 Condition 接口

相比 synchronized,Lock 提供了更灵活的同步机制,而 Condition 可以替代 wait()、notify() 和 notifyAll(),并支持多个等待条件。

ReentrantLock:常用于显式锁控制,可以提供公平锁机制(按获取锁的顺序进行调度)。Condition:类似于 Object 的 wait()、notify(),可以创建多个 Condition 来进行复杂的线程协调。示例:

import java.util.concurrent.locks.Condition;

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

class BoundedBuffer {

private final int[] buffer;

private int count, in, out;

private final Lock lock = new ReentrantLock();

private final Condition notFull = lock.newCondition();

private final Condition notEmpty = lock.newCondition();

public BoundedBuffer(int size) {

buffer = new int[size];

}

public void put(int value) throws InterruptedException {

lock.lock();

try {

while (count == buffer.length) {

notFull.await(); // 等待缓冲区未满

}

buffer[in] = value;

in = (in + 1) % buffer.length;

count++;

notEmpty.signal(); // 唤醒消费线程

} finally {

lock.unlock();

}

}

public int take() throws InterruptedException {

lock.lock();

try {

while (count == 0) {

notEmpty.await(); // 等待缓冲区非空

}

int value = buffer[out];

out = (out + 1) % buffer.length;

count--;

notFull.signal(); // 唤醒生产线程

return value;

} finally {

lock.unlock();

}

}

}

public class LockConditionExample {

public static void main(String[] args) {

BoundedBuffer buffer = new BoundedBuffer(5);

Thread producer = new Thread(() -> {

try {

for (int i = 0; i < 10; i++) {

buffer.put(i);

System.out.println("Produced: " + i);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

});

Thread consumer = new Thread(() -> {

try {

for (int i = 0; i < 10; i++) {

int value = buffer.take();

System.out.println("Consumed: " + value);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

});

producer.start();

consumer.start();

}

}

使用场景:适用于需要显式锁定、更复杂的条件等待场景,比如多条件同步、多生产者-消费者模型。

4. java.util.concurrent 包的并发工具

Java 提供了 java.util.concurrent 包下的一系列高级并发工具类来简化线程间通信。

BlockingQueue:线程安全的队列,常用于生产者-消费者模式。CountDownLatch:允许一个或多个线程等待其他线程完成某些操作。CyclicBarrier:多个线程在某个点上相互等待,直到所有线程到达该点。Semaphore:用于控制对资源的访问许可。Exchanger:用于两个线程之间交换数据。

相关作品

excel单元格中的空格怎么去掉 365500元大写

excel单元格中的空格怎么去掉

❤️ 435 📅 07-04