Java中实现线程间通信的实例教程

下面我将为您详细讲解“Java中实现线程间通信的实例教程”的完整攻略。

什么是线程间通信

线程是 Java 中最基本的并发编程单元,线程之间的通信是指多个线程在访问共享资源过程中,通过某种协作机制对资源实现共享和互斥访问的过程。线程间通信是 Java 并发编程中的核心概念之一。

线程间通信实现方式

Java 中实现线程间通信一般有三种方式:

  • 共享内存
  • 消息传递
  • 管程法

在本教程中,我们将主要通过消息传递和管程法来实现线程间的通信。

消息传递实现线程间通信

使用消息传递实现线程间通信需要依赖于 Java 中提供的两个类,即 wait()notify() 方法。其中,wait() 方法会使当前线程等待,直到另一个线程调用该对象的 notify()notifyAll() 方法通知该线程等待结束。通知时可以通过锁机制唤醒一个等待中的线程,也可唤醒全部等待中的线程。

接下来,我们将通过一个生产者和消费者的例子来说明如何使用消息传递实现线程间的通信:

class Store {
    private int i = 0;

    public synchronized void put() {
        while (i >= 5) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " put " + (++i));
        notifyAll();
    }

    public synchronized void get() {
        while (i <= 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName() + " get " + (i--));
        notifyAll();
    }
}

class Producer implements Runnable {
    private Store store;

    public Producer(Store store) {
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.put();
        }
    }
}

class Consumer implements Runnable {
    private Store store;

    public Consumer(Store store) {
        this.store = store;
    }

    @Override
    public void run() {
        while (true) {
            store.get();
        }
    }
}

public class MessageCommunicationDemo {
    public static void main(String[] args) {
        Store store = new Store();
        new Thread(new Producer(store)).start();
        new Thread(new Consumer(store)).start();
        new Thread(new Producer(store)).start();
        new Thread(new Consumer(store)).start();
    }
}

上面的代码中,Store 类代表一个仓库,具有 put()get() 方法,其中 put() 方法将商品放入仓库中,get() 方法将商品从仓库中取出。由于仓库中的商品数量有极限,因此在 put()get() 方法中,首先判断商品是否已经满了或空了,如果是,则调用 wait() 方法将线程挂起,直到其他线程唤醒。当商品数量发生变化时,调用 notifyAll() 方法唤醒其他线程继续运行。

通过该例子,我们可以清楚的了解到通过消息传递实现线程间的通信的详细过程。

管程法实现线程间通信

管程是一种结构,包含共享变量及操作这些变量的过程,其中,共享变量一般配合条件变量使用以实现同步。Java 中的管程是通过 synchronizedwait()notify() 方法来实现的。当一个线程需要调用管程时,需要持有该管程的锁。当需要等待某个条件满足时,线程可以通过 wait() 方法将自己挂起,当条件被满足时,其他线程调用 notify() 方法,唤醒之前挂起的线程继续执行。管程法比消息传递的实现方式更加简单。

接下来,我们将通过一个银行取款的例子来说明如何使用管程法实现线程间的通信:

class Account {
    private int balance = 100;

    public synchronized void withdraw(int amount) {
        while (balance < amount) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        balance -= amount;
        System.out.println(Thread.currentThread().getName() + " withdraw " + amount + ", balance is " + balance);
    }

    public synchronized void deposit(int amount) {
        balance += amount;
        System.out.println(Thread.currentThread().getName() + " deposit " + amount + ", balance is " + balance);
        notifyAll();
    }
}

class WithdrawThread implements Runnable {
    private Account account;

    public WithdrawThread(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        while (true) {
            account.withdraw(70);
        }
    }
}

class DepositThread implements Runnable {
    private Account account;

    public DepositThread(Account account) {
        this.account = account;
    }

    @Override
    public void run() {
        while (true) {
            account.deposit(100);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class PipeCommunicationDemo {
    public static void main(String[] args) {
        Account account = new Account();
        new Thread(new WithdrawThread(account)).start();
        new Thread(new DepositThread(account)).start();
    }
}

上面的代码中,Account 类代表一个银行账户,具有 withdraw()deposit() 方法,其中 withdraw() 方法用于从账户中取款,deposit() 方法用于往账户中存款。由于账户中的余额可能不足,因此在 withdraw() 方法中,要判断余额是否充足,如果不足则调用 wait() 方法挂起线程,等待其他线程存款后余额增加。当余额充足时,其他线程通过 notifyAll() 方法唤醒之前挂起的线程继续执行。

通过该例子,我们可以清楚的了解到通过管程法实现线程间的通信的详细过程。

以上就是 Java 中实现线程间通信的完整攻略。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中实现线程间通信的实例教程 - Python技术站

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

相关文章

  • Java语言打印九九乘法表

    Java语言打印九九乘法表可以有多种实现方式,以下给出两种示例说明: 使用双重循环 代码示例: public class MultiplicationTable { public static void main(String[] args) { for (int i = 1; i <= 9; i++) { for (int j = 1; j <…

    Java 2023年5月26日
    00
  • struts2实现文件下载功能

    下面我为你详细讲解“struts2实现文件下载功能”的完整攻略。 1. 确定文件路径和文件名 在进行文件下载功能的实现之前,我们需要先确定文件的路径和文件名。一般而言,可以将文件路径和文件名存储在数据库或配置文件中。在本次实例中,我们将文件保存在了项目根目录下的uploads目录中,因此文件路径和文件名可以如下方式进行定义: String filePath …

    Java 2023年5月20日
    00
  • Abp.NHibernate连接PostgreSQl数据库的方法

    Abp框架是一个基于ASP.NET Boilerplate的ASP.NET Core应用程序开发框架,支持多种ORM框架。NHibernate是其中一个优秀的ORM框架,可以与PostgreSQL数据库进行连接,下面是连接的方法: 步骤一:安装相关包 在项目的Nuget包控制台中,安装以下三个包: Install-Package Abp.NHibernate…

    Java 2023年5月19日
    00
  • Java中的代码重构如何避免异常?

    Java中的代码重构是一种重要的技术手段,可以提高代码的可读性、可维护性和可测试性。其中,如何避免异常是非常关键的一点。以下是详细的攻略: 理解代码重构的目的和原则 代码重构的目的是改善代码的质量,不影响代码功能。代码重构的原则包括:确保代码的正确性、消除代码的冗余、提高代码的可读性、提高代码的可维护性和可测试性。 意识到异常的重要性 异常是Java中一个非…

    Java 2023年4月27日
    00
  • Java关于数组的介绍与使用

    Java关于数组的介绍与使用 数组是一组数据的集合,是Java中的一种基本的数据结构类型,具有以下特点: 数组是一种固定大小,且元素类型相同的数据结构; 数组的下标从0开始; 数组在创建时需要指定长度,且长度不可改变; 数组可以存储基本类型和引用类型。 声明和初始化数组 声明数组的语法格式如下: dataType[] arrayName;//推荐 或 dat…

    Java 2023年5月26日
    00
  • JavaWeb使用mvc模式实现登录功能

    JavaWeb使用MVC模式实现登录功能涉及以下三个模块: Model:负责处理业务逻辑和数据操作 View:负责用户交互界面的展示 Controller:负责控制程序流程和协调 Model 和 View 下面是实现步骤: 创建数据库表格,用于存储用户信息。 示例 SQL 语句: CREATE TABLE `t_user` ( `id` int(11) un…

    Java 2023年6月15日
    00
  • Java中如何获取mysql连接的3种方法总结

    下面我讲一下Java中如何获取MySQL连接的3种方法总结。 1. JDBC DriverManager JDBC DriverManager是Java JDBC API提供的一种获取数据库连接的方式,使用此方法需要导入java.sql.DriverManager类。下面是一个使用JDBC DriverManager获取MySQL连接的示例。 import …

    Java 2023年5月19日
    00
  • Java中Spock框架Mock对象的方法经验总结

    Java中Spock框架Mock对象的方法经验总结 简介 Spock是一个基于Geb和JUnit的开源Java测试框架,它支持BDD(行为驱动开发)并提供了很多有用的功能。其中一个最常用的功能是Mock对象。这篇攻略将介绍如何在Java中使用Spock框架Mock对象。 Mock对象的定义 Mock对象是经过模拟的对象,代替了真实的对象。Mock对象可以控制…

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