当前位置: 首页 > article >正文

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. LockCondition 接口

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

  • ReentrantLock:常用于显式锁控制,可以提供公平锁机制(按获取锁的顺序进行调度)。
  • Condition:类似于 Objectwait()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:用于两个线程之间交换数据。

http://www.kler.cn/a/430281.html

相关文章:

  • WandB使用笔记
  • Eclipse配置Tomcat服务器(最全图文详解)
  • 数据结构:LinkedList与链表—面试题(三)
  • BeanFactory与factoryBean 区别,请用源码分析,及spring中涉及的点,及应用场景
  • GoChina备案管家
  • STM32 拓展 电源控制
  • WinForm(C/S)项目中使用矢量字体(FontAwsome、Elegant)图标
  • 使用Python实现科学计算工具:数据分析的利器
  • 论文阅读 - Context De-confounded Emotion Recognition
  • Java 创建图形用户界面(GUI)组件详解之下拉式菜单(JMenu、JMenuItem)、弹出式菜单(JPopupMenu)等
  • es字段修改
  • pytorch多GPU训练教程
  • 快速搭建SpringBoot3+Vue3+ElementPlus管理系统
  • C# 关于实现保存数据以及数据溯源推送
  • 传奇996_53——后端ui窗口局部刷新
  • 3D 生成重建022-GRM基于大模型和多视图扩散模的D生成模型
  • 常见限流算法
  • 【Leetcode Top 100】94. 二叉树的中序遍历
  • 观察者模式的理解和实践
  • vue的指令
  • Python 网络爬虫进阶:突破数据采集的边界
  • 【金猿CIO展】海博科技总经理兼CIO韩东明:大数据与大模型,驱动智能运维的新引擎...
  • 在Excel中实现选中单元格行列变色的功能
  • 基于SpringBoot实现验证码功能
  • C# WinForm —— 39 40 41 42 DataGridView 介绍与使用
  • k8s 之 Deployment