同步 && 异步

目录

1  什么是同步

1.1  定义

1.2  特点

1.3  示例

1.4  优点

1.5  缺点

2  什么是异步

2.1  定义

2.2  特点

2.3   示例

2.4  优点 

 2.5  缺点 

3  同步和异步的选择

3.1  什么时候使用同步:

3.2  什么时候使用异步:

4  举例对比

4.1  同步操作更好的场景

4.2  异步操作更好的场景

5  总结


1  什么是同步

1.1  定义

       同步操作是指在调用一个方法或函数时,调用者必须等待这个方法或函数执行完成之后,才能继续执行后续代码。换句话说,调用是阻塞的,直到操作完成为止。


1.2  特点

  • 调用者必须等待操作完成。
  • 操作是顺序执行的,只有当前操作完成后,程序才会继续执行下一个操作。

1.3  示例

         假设你要从数据库中获取一条数据并打印出来:

public void getDataAndPrint() {
    String data = getDataFromDatabase(); // 同步操作,必须等待数据获取完成
    System.out.println(data); // 获取到数据后才能执行这行代码
}

         在这个示例中,程序会等待 getDataFromDatabase() 完成(例如,数据库查询完成)后,才会继续执行 System.out.println(data)


1.4  优点

  • 代码逻辑简单,容易理解和调试。
  • 程序执行的顺序和操作的顺序一致,便于跟踪

1.5  缺点

  • 如果某个同步操作耗时较长,会导致整个程序的响应速度变慢,无法处理其他任务,容易出现“阻塞”现象。
  • 在处理 I/O 操作(如网络请求、文件读取)时,等待时间长可能会影响用户体验。

2  什么是异步

2.1  定义

       异步操作是指在调用一个方法或函数时,调用者不需要等待这个操作完成就可以继续执行后续代码。调用是非阻塞的,操作在后台执行,操作完成后通过回调或事件通知调用者。


2.2  特点

  • 调用者无需等待操作完成,操作在后台执行。
  • 操作完成后,结果会通过回调函数、事件通知或未来对象(如 FutureCompletableFuture)传递给调用者。

2.3   示例

        假设你要异步从数据库中获取数据并在获取完成后打印:

public void getDataAndPrintAsync() {
    CompletableFuture.supplyAsync(() -> getDataFromDatabase()) // 异步操作
                     .thenAccept(data -> System.out.println(data)); // 数据获取完成后执行
    System.out.println("Continue executing other code"); // 不等待数据获取,继续执行
}

 在这个示例中,getDataFromDatabase() 在后台执行,System.out.println("Continue executing other code") 会立即执行,不需要等待数据库查询完成。当数据获取完成后,thenAccept 内的代码块才会执行。


2.4  优点 

  • 提高程序的响应速度:不需要等待耗时操作完成,程序可以继续执行其他任务。
  • 更好地利用系统资源,特别是在 I/O 操作密集型的应用中,异步处理可以显著提高系统的吞吐量和效率。

 2.5  缺点 

  • 代码逻辑复杂:异步代码通常涉及回调、事件处理或 Future 对象管理,理解和调试这些代码比同步代码困难。
  • 由于操作是在后台执行,容易出现竞态条件(race condition),需要额外的同步机制来保证线程安全。

3  同步和异步的选择

3.1  什么时候使用同步

  • 操作耗时较短,且不影响程序整体性能时。
  • 代码逻辑简单且不涉及大量 I/O 操作时。
  • 需要按照严格的顺序执行一系列操作时。

3.2  什么时候使用异步

  • 操作耗时较长,特别是涉及 I/O 操作(如网络请求、文件读取、数据库访问)时。
  • 需要并发处理多个任务,且希望在某些操作执行时继续处理其他任务时。
  • 希望提高系统的响应速度和资源利用率时,特别是在用户交互密集的应用中。

4  举例对比

4.1  同步操作更好的场景

        (1)场景:银行转账系统

        在银行的转账系统中,转账操作通常涉及到从一个账户中扣款并将资金转入另一个账户。这两个操作必须按照严格的顺序执行,并且在整个过程中不允许有任何中断或并发操作导致数据不一致。因此,在这种场景下,同步操作是更好的选择。

        (2)示例代码:

public class BankService {

    // 同步转账操作
    public synchronized void transfer(Account fromAccount, Account toAccount, double amount) {
        // 检查余额
        if (fromAccount.getBalance() >= amount) {
            // 从源账户扣款
            fromAccount.withdraw(amount);
            
            // 向目标账户存款
            toAccount.deposit(amount);
            
            System.out.println("转账成功:" + amount + " 从 " + fromAccount.getId() + " 到 " + toAccount.getId());
        } else {
            System.out.println("余额不足,转账失败。");
        }
    }
}

class Account {
    private String id;
    private double balance;

    public Account(String id, double balance) {
        this.id = id;
        this.balance = balance;
    }

    public synchronized void withdraw(double amount) {
        balance -= amount;
    }

    public synchronized void deposit(double amount) {
        balance += amount;
    }

    public double getBalance() {
        return balance;
    }

    public String getId() {
        return id;
    }
}

         (3)分析

  • 同步操作的必要性:在转账过程中,如果操作不按顺序执行,可能会导致资金丢失或账户余额不一致的情况。因此,必须确保从账户中扣款和存入目标账户的操作是同步的。
  • 同步的优势:同步操作确保了数据的一致性和完整性,在关键的金融交易中非常重要。

4.2  异步操作更好的场景

        (1)场景:发送批量邮件

假设你管理一个电商平台,每当有新产品上架时,需要向成千上万的用户发送通知邮件。如果你采用同步操作,每次发送邮件都需要等待上一个邮件发送完成,这将导致整个过程耗时过长,且无法在邮件发送期间处理其他任务。在这种情况下,异步操作是更好的选择。

        (2)示例代码

import java.util.List;
import java.util.concurrent.CompletableFuture;

public class EmailService {

    // 异步发送邮件操作
    public void sendBatchEmails(List<String> emailAddresses, String subject, String content) {
        for (String email : emailAddresses) {
            // 异步发送每封邮件
            CompletableFuture.runAsync(() -> sendEmail(email, subject, content));
        }
        System.out.println("批量邮件发送任务已启动,正在后台处理中...");
    }

    // 模拟邮件发送
    private void sendEmail(String email, String subject, String content) {
        try {
            // 模拟邮件发送的耗时操作
            Thread.sleep(1000);
            System.out.println("邮件已发送到:" + email);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

         (3)分析

  • 异步操作的必要性:批量发送邮件的操作较耗时,尤其是在处理大量收件人时。采用异步操作可以在邮件发送的同时继续处理其他任务,例如响应用户请求或处理其他事务。
  • 异步的优势:异步操作不会阻塞主线程,能够显著提高系统的响应速度和吞吐量。在需要处理大量并发任务时,异步操作更为高效。

5  总结

  • 同步操作:简单、顺序执行,适合不涉及长时间等待的操作。
  • 异步操作:非阻塞、提高并发处理能力,适合长时间等待或需要并发处理的场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颜回.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值