深入探究一下Java中不同的线程间数据通信方式

深入探究Java中不同的线程间数据通信方式

多线程编程中,线程的运行是并发的,若多个线程共享同一块数据,需要设置线程间数据通信以确保线程的安全并发执行。Java提供了多种线程间数据通信的方式。

1. 共享变量方式

在多线程的场景中,共享变量是指被多个线程共同使用和修改的变量。这种方式是最简单的线程间通信方式,可以在任何地方使用,但要注意线程安全问题。

在Java中,最常用的共享变量方式是 volatile 和 synchronized,分别对应修改变量与锁同步。

1.1 volatile

volatile关键字在多线程编程中保证数据的同步,能够强制到线程内存中读取变量而不是线程缓存,从而确保数据的可见性。

示例:

public class VolatileTest {
    private volatile boolean flag = false;

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!flag) {
                    // do something
                }
                System.out.println("Thread is end.");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                flag = true;
            }
        }).start();
    }
}

在上面的示例中,通过 volatile 关键字保证了 flag 的可见性,确保了第二个线程对 flag 的修改能够被第一个线程同步到。

1.2 synchronized

synchronized是Java中一个重要的关键字,在多线程的场景中,被用来管理共享数据的访问。通过 synchronized 锁机制可以保证代码的原子执行。

示例:

public class SynchronizedTest {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
                System.out.println("Thread is end.");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    increment();
                }
                System.out.println("Thread is end.");
            }
        }).start();
    }
}

在上面的示例中,线程共同对 count 进行操作,通过 synchronized 关键字锁住 increment() 方法,确保了对 count 的操作是原子性的。

2. wait/notify方式

Java中 wait/notify方式是一种非常重要的线程间通信方式,他们一起被用来实现线程的同步。wait可以将线程挂起,notify可以唤醒其它线程。

2.1 wait

wait()方法挂起当前线程,此方法必须在synchronized代码块或方法内调用。wait()会释放线程占用的锁,让其它线程进入synchronized代码块或方法内。

示例:

public class WaitNotifyTest {
    private final Object monitor = new Object();

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (monitor) {
                    System.out.println("Thread1 start.");
                    try {
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Thread1 end.");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (monitor) {
                    System.out.println("Thread2 start.");
                    monitor.notify();
                    System.out.println("Thread2 end.");
                }
            }
        }).start();
    }
}

在上面的示例中,通过 notify() 方法唤醒线程1。由于 wait() 方法释放了锁,线程2 执行完成后,线程1 才会执行。

2.2 notify

notify() 方法唤醒在此对象监视器上等待的一个线程,如果有多个线程等待,将随机唤醒其中的一个。

示例:

public class WaitNotifyTest {
    private final Object monitor = new Object();

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (monitor) {
                    System.out.println("Thread1 start.");
                    try {
                        monitor.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Thread1 end.");
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (monitor) {
                    System.out.println("Thread2 start.");
                    monitor.notify();
                    System.out.println("Thread2 end.");
                }
            }
        }).start();
    }
}

在上面的示例中,通过 notify() 方法唤醒线程1。由于 wait() 方法释放了锁,线程2 执行完成后,线程1 才会执行。

3. Lock/Condition方式

Lock/Condition方式是一种替代synchronized的方式,它们的功能类似,但是比synchronized更加灵活。按照具体的场景,选择合适的方式。

示例:

public class LockConditionTest {
    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("Thread1 start.");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread1 end.");
                lock.unlock();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                lock.lock();
                System.out.println("Thread2 start.");
                condition.signal();
                System.out.println("Thread2 end.");
                lock.unlock();
            }
        }).start();
    }
}

在上面的示例中,一个 lock 指定了访问临界区的线程,一个 condition 指定了需要等待的线程,当需要等待时,等待线程在 condition 上等待。

结论

在多线程编程中,线程间数据通信方式很多,选择合适的方式可以提高程序的性能和效率,保证代码的正确性和可读性。以上介绍的共享变量方式、wait/notify方式、Lock/Condition方式是其中最常用的方式,这里还需要提醒大家,线程安全问题是多线程编程中需要注意的关键点,需要谨慎对待。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:深入探究一下Java中不同的线程间数据通信方式 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月19日

相关文章

  • 在idea中将创建的java web项目部署到Tomcat中的过程图文详解

    下面我将为您详细讲解在Idea中将创建的Java Web项目部署到Tomcat中的完整攻略。 准备工作 在开始部署之前,我们需要先进行如下准备工作: 安装JDK环境 安装Tomcat服务器 安装Idea开发工具 创建Java Web项目 在Idea中创建Java Web项目的步骤如下: 打开Idea开发工具 点击”File” -> “New” -&gt…

    Java 2023年6月2日
    00
  • java容器详细解析

    Java容器详细解析 在Java中,容器是一种可以存储和检索对象的数据结构。Java提供了各种类型的容器,包括List、Set、Map等等。本文将通过详细解析Java容器,让您了解Java中各种容器类型的使用方法和优缺点。 List容器 List容器是一种有序的容器,允许元素重复。在Java中,常用的List容器有ArrayList和LinkedList。 …

    Java 2023年5月26日
    00
  • java Struts2框架下实现文件上传功能

    实现文件上传功能在Web应用程序中非常常见。在Java Web应用程序中,常用的框架之一是Struts2框架。下面是实现文件上传功能的完整攻略。 步骤1:添加依赖 要在Struts2应用程序中实现文件上传功能,我们需要添加一些依赖项。具体来说,我们需要添加以下依赖项: <dependency> <groupId>org.apache.…

    Java 2023年5月20日
    00
  • SpringMVC如何获取表单数据(radio和checkbox)

    获取表单数据是Web应用程序中最常见的任务之一。SpringMVC在处理表单数据方面提供了许多便捷的方法,包括获取单选框和复选框的值。 获取单选框的值 客户端可以在多个单选按钮之间进行选择。一组单选按钮被视为一组,必须具有相同的名称。SpringMVC在控制器中提供了几种方法来获取选定的单选按钮值。下面是两条示例说明: 示例1:使用@RequestParam…

    Java 2023年5月26日
    00
  • Java SpringBoot自动装配原理详解及源码注释

    Java SpringBoot自动装配原理详解及源码注释是一篇关于SpringBoot自动装配原理的技术文章。文章介绍了SpringBoot如何实现自动装配,包括SpringBoot自动配置的流程和源代码注释。攻略包含以下内容: 1、什么是SpringBoot自动装配 首先,我们需要知道什么是SpringBoot自动装配。当我们使用SpringBoot框架时…

    Java 2023年5月19日
    00
  • Java对称加密算法DES实例详解

    Java对称加密算法DES实例详解 什么是对称加密算法 对称加密算法:使用相同的密钥进行加密和解密。对称加密算法的加密速度快,但密钥的管理和分配比较困难。 什么是DES加密算法 DES(Data Encryption Standard)是一种数据加密的标准,它是一种对称加密算法,使用密钥对数据进行加密和解密。DES算法已广泛应用于各种安全领域,如金融、电子政…

    Java 2023年5月19日
    00
  • Java基础-Java基本数据类型

    Java基础-Java基本数据类型 Java中的数据类型分为两类: 基本数据类型和引用数据类型。基本数据类型共8种,分别是byte、short、int、long、float、double、boolean、char。本文将详细介绍Java的基本数据类型。 byte byte类型是最小的数据类型,占1个字节(byte),取值范围是-128到127。当我们需要存储…

    Java 2023年5月26日
    00
  • Mybatis-Plus批量插入用法详解

    Mybatis-Plus批量插入用法详解 什么是Mybatis-Plus? Mybatis-Plus 是一个 Mybatis 的增强工具,在 Mybatis 的基础上进行了简单的封装,使其用起来更加方便和简洁。它提供了一系列的增强功能,诸如自动化 CRUD 操作、分页、排序、关联查询等功能,可以大大提高开发效率和代码质量。 Mybatis-Plus批量插入的…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部