阻塞和非阻塞

在介绍阻塞和非阻塞之前,我们先来了解一下多线程间一个重要的概念——临界区。

临界区——一种公有的资源或者共享数据,它可以被多个线程使用。临界区资源一次只能被一个线程使用,其它线程必须等待上一个线程
执行完成之后,才能使用。临界区资源是多线程之间重要保护对象,当临界区资源同时被多个线程访问时,容易出现错误。
代码示例:
 
 
/**
 * @author php
 * @date 2018/7/2
 */
public class CriticalRegion {
    //定义1000元
    public static Integer money = 1000;

    public static void main(String[] args) throws InterruptedException {
        //定义公共资源
        CriticalRegion criticalRegion = new CriticalRegion();
        //定义10个线程来购物
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
                criticalRegion.shop();
            });
        }
        Thread.sleep(1000);
        System.out.println("最终还有:" + CriticalRegion.money);
        executorService.shutdown();
    }

    //我们每次购物使用100块钱
    public  void shop() {
        money = money - 100;
        System.out.println("使用了100元,我还有:" + CriticalRegion.money);
    }
}

执行结果:从中可以看出,多个线程,同时操作临界区资源时,容易导致操作资源错误。在大部分情况下,这是一个很严重的问题。
大家可以多执行几次,看看结果有什么不同。


现在,我们修改一下shop()方法,在方法上加上sychronized。执行结果:sychronized可以让临界区资源,一次只能被一个线程访问,

从而结果正确。


临界区资源,在使用多线程时,要格外的注意,以免结果千奇百怪。

在我们了解临界区之后,再来了解阻塞和非阻塞的概念。

阻塞和非阻塞通常被用来形容多线程间的相互影响。当一个线程占用了临界区资源,那么其它需要使用这个资源的线程都必须在这个临界区上等待。等待会导致线程挂起,这样就形成了阻塞。如果占用资源的线程一直没有释放资源,那么其它的线程在这个临界区上都不能继续工作。

相反,非阻塞表明多个线程之间的执行是不会相互影响的。

通常,我们使用synchronized关键字,ReentrantLock(重入锁)时,我们得到的线程就是阻塞线程。阻塞线程在执行代码前,都会尝试得到临界区资源的锁,如果得不到,线程就会一直挂起,直到临界区资源释放。
<think>好的,我现在需要帮助用户理解阻塞非阻塞在编程中的区别。首先,我应该回顾一下已有的知识,确保自己对这两个概念有清晰的理解。根据提供的引用资料,阻塞非阻塞主要关注的是进程在进行I/O操作时的状态。 首先,阻塞IO是当进程发起一个I/O操作后,必须等待该操作完成才能继续执行后续代码。例如,当程序调用一个读取文件的函数时,如果使用阻塞模式,程序会一直停在那个函数调用处,直到文件读取完毕才会继续执行。这种情况下,进程会被挂起,无法做其他事情,导致资源利用率不高。引用中提到的阻塞IO属于同步操作,因为程序需要等待操作完成[^1]。 接下来是非阻塞IO。非阻塞模式下,进程发起I/O操作后,可以立即返回并继续执行其他任务,而不必等待操作完成。程序需要不断轮询来检查操作是否完成。例如,非阻塞的文件读取会立即返回,如果数据还没准备好,函数可能会返回一个错误码,程序可以继续处理其他逻辑,稍后再尝试读取。非阻塞可以是同步的,因为程序仍然需要自己检查状态,尽管不需要一直等待。不过,引用中也提到非阻塞可能是异步的,但需要结合具体的实现方式来看[^2]。 用户的问题是关于阻塞非阻塞的区别,特别是在编程中的表现。我需要用通俗易懂的语言解释这两个概念,并结合例子帮助理解。同时,我需要确保符合用户的要求,使用中文回答,结构清晰,分步骤说明。 接下来要检查是否有相关的例子应用场景可以说明。例如,在网络编程中,阻塞模式下,当服务器等待客户端连接时,如果没有连接到来,服务器线程会被阻塞,无法处理其他请求。而非阻塞模式下,服务器可以继续处理其他任务,定期检查是否有新连接。 还需要注意同步异步的区别,但用户主要关注阻塞非阻塞。根据引用,同步异步关注任务执行方式,而阻塞非阻塞关注进程状态。例如,同步操作可以是阻塞非阻塞的,而异步通常是非阻塞的,但可能有例外。 总结区别时,可以列出几点:等待方式、资源利用、实现复杂度、适用场景等。例如,阻塞会一直等待,导致资源浪费;非阻塞允许程序继续执行,提高效率,但需要更复杂的逻辑来处理轮询回调。 最后,生成相关问题,帮助用户进一步探索。比如,非阻塞IO的实现方式,或者在不同编程语言中的应用案例。</think>### 阻塞非阻塞的区别 在编程中,**阻塞****非阻塞**描述了程序在执行输入/输出(I/O)操作时的行为模式,核心区别在于**程序是否会等待操作完成**再继续执行后续代码。以下是具体分析: --- #### 1. **阻塞(Blocking)** - **定义**:当程序发起一个I/O操作(如读取文件、网络请求)时,必须等待该操作**完全结束**后,才能继续执行后续逻辑。 - **特点**: - **同步等待**:线程会被挂起,无法执行其他任务[^1]。 - **资源占用**:若操作耗时较长,会导致线程长时间闲置,降低系统吞吐量。 - **实现简单**:代码逻辑直观,适合简单场景。 - **示例**: ```python # 阻塞式读取文件 data = file.read() # 程序在此处等待,直到文件读取完成 print("继续执行...") ``` --- #### 2. **非阻塞(Non-blocking)** - **定义**:程序发起I/O操作后**立即返回**,无需等待结果,可以继续执行后续代码。需要通过**轮询****回调机制**获取操作结果。 - **特点**: - **异步同步**:非阻塞可能是同步的(如轮询检查状态),也可能是异步的(如回调通知)。 - **资源高效**:线程可执行其他任务,提升系统并发能力。 - **实现复杂**:需要处理状态检查事件驱动逻辑。 - **示例**: ```python # 非阻塞式网络请求(伪代码) socket.set_nonblocking(True) try: data = socket.recv(1024) # 立即返回,若数据未就绪则抛出异常 except BlockingIOError: print("数据未就绪,继续处理其他任务...") ``` --- #### 关键区别总结 | **特征** | **阻塞** | **非阻塞** | |----------------|-----------------------------|-------------------------------| | **等待方式** | 同步等待操作完成 | 立即返回,通过轮询回调获取结果 | | **资源利用** | 线程闲置,效率低 | 线程可复用,效率高 | | **实现复杂度** | 简单 | 复杂(需处理状态/事件) | | **适用场景** | 简单任务、低并发 | 高并发、实时响应需求 | --- #### 扩展说明 - **阻塞与同步的关系**:阻塞一定是同步的(需等待操作完成),但同步不一定是阻塞的(例如非阻塞轮询仍属于同步)。 - **非阻塞与异步的关系**:异步通常是非阻塞的(如回调通知),但非阻塞也可以通过同步轮询实现。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值