java实现线程阻塞式方法

 更新时间:2024年10月23日 10:41:05   作者:Flying_Fish_Xuan  
Java阻塞式方法会使线程暂停执行,不占用CPU资源直至条件满足,常见阻塞方法如Thread.sleep()、Object.wait()和I/O操作,具有一定的参考价值,感兴趣的可以了解一下

在Java编程中,阻塞式方法(blocking methods)指的是那些在被调用后,当前线程会暂停执行,直到某些条件满足或事件发生后才继续运行的方法。在这种情况下,当前线程会进入阻塞状态(blocking state),并且不会占用CPU资源,但也无法执行任何其他操作,直到该方法完成或条件满足。

1. 阻塞式方法的特点

阻塞式方法通常有以下几个特点:

  • 暂停线程执行:调用阻塞式方法的线程会被挂起,进入阻塞状态,直到方法返回或条件满足为止。
  • 不占用CPU资源:阻塞状态下的线程不会消耗CPU时间片,因此不会对系统性能造成直接负担,但它会阻止线程执行其他任务。
  • 依赖外部条件:阻塞式方法通常等待某种外部条件或事件,例如I/O操作完成、锁释放、线程被唤醒等。
  • 潜在的影响:如果没有妥善处理,阻塞式方法可能导致线程长时间处于等待状态,进而影响应用程序的响应能力和并发性能。

2. Java中的常见阻塞式方法

在Java中,有许多常见的阻塞式方法,它们通常出现在多线程编程、I/O操作和网络编程中。

2.1 Thread.sleep()

Thread.sleep(long millis) 是一个阻塞式方法,用于使当前线程休眠指定的毫秒数。在此期间,线程处于阻塞状态,不会执行任何操作,直到指定的时间过去。

public class SleepExample {
    public static void main(String[] args) {
        System.out.println("Thread is going to sleep...");
        try {
            Thread.sleep(2000);  // 线程休眠2秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread woke up!");
    }
}

在这个例子中,Thread.sleep(2000) 使当前线程阻塞2秒,之后继续执行。

2.2 Object.wait()

Object.wait() 是一个阻塞式方法,它使当前线程进入等待状态,直到其他线程调用 notify() 或 notifyAll() 方法唤醒它。通常用于线程间的同步和通信。

public class WaitNotifyExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("Thread is waiting...");
                    lock.wait();  // 线程进入等待状态
                    System.out.println("Thread is resumed!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("Thread is notifying...");
                lock.notify();  // 唤醒等待的线程
            }
        });

        waitingThread.start();
        try {
            Thread.sleep(1000);  // 确保waitingThread进入等待状态
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        notifyingThread.start();
    }
}

在这个例子中,wait() 方法使 waitingThread 进入等待状态,直到 notifyingThread 调用 notify() 方法将其唤醒。

2.3 Thread.join()

Thread.join() 是一个阻塞式方法,它让当前线程等待另一个线程完成执行后再继续。例如,如果在主线程中调用 t.join(),主线程将被阻塞,直到线程 t 运行完毕。

public class JoinExample {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("Thread finished execution");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t.start();

        try {
            t.join();  // 主线程等待t线程完成
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Main thread continues after t finishes");
    }
}

在这个例子中,t.join() 使主线程阻塞,直到 t 线程执行完毕。

2.4 I/O 操作中的阻塞方法

在Java中,I/O操作(如文件读写、网络通信)通常是阻塞式的。例如,InputStream.read() 方法在没有数据可供读取时会使当前线程阻塞,直到数据可用或达到流的末尾。

import java.io.FileInputStream;
import java.io.IOException;

public class FileReadExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("example.txt")) {
            int data;
            while ((data = fis.read()) != -1) {  // read() 是阻塞式方法
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,fis.read() 方法会阻塞,直到读取到数据或文件的末尾。

2.5 网络编程中的阻塞方法

在网络编程中,Socket.accept()SocketInputStream.read() 等方法也是阻塞式的。例如,ServerSocket.accept() 方法会阻塞当前线程,直到有客户端连接到服务器。

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerSocketExample {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8080)) {
            System.out.println("Server is listening on port 8080...");
            Socket clientSocket = serverSocket.accept();  // accept() 是阻塞式方法
            System.out.println("Client connected: " + clientSocket.getInetAddress());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个例子中,serverSocket.accept() 方法会阻塞,直到有客户端连接到服务器。

3. 阻塞式方法的优缺点

优点

  • 简单易用:阻塞式方法的逻辑简单、易于理解,开发者不需要处理复杂的异步逻辑或回调。
  • 资源管理容易:由于阻塞式方法通常不会频繁占用CPU资源,因此在处理I/O操作时比较高效。
  • 自然的控制流:阻塞式方法遵循自然的控制流,代码更加直观,不需要分离处理逻辑。

缺点

  • 潜在的性能问题:如果线程长时间阻塞,会导致线程池中的线程被占用,可能导致应用程序的响应能力下降或死锁。
  • 可能导致线程饥饿:在多线程环境中,长时间阻塞可能导致其他线程无法获得执行机会,进而引发线程饥饿问题。
  • 不适用于高并发场景:在高并发应用中,过多的阻塞式方法可能导致线程数量激增,增加内存开销和线程上下文切换的开销。

4. 替代方案:非阻塞式方法与异步编程

由于阻塞式方法的固有缺陷,尤其是在高并发和实时性要求高的系统中,通常会考虑使用非阻塞式方法或异步编程模型。

4.1 非阻塞式I/O

Java NIO(New I/O)库引入了非阻塞I/O,允许线程在没有数据可用时继续执行其他任务。通过选择器(Selector)模型,可以实现一个线程管理多个I/O通道的操作,从而提高并发性能。

import java.io.IOException;
import java.nio.channels.*;
import java.net.InetSocketAddress;

public class NonBlockingServerExample {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(8080));
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            for (SelectionKey key : selector.selectedKeys()) {
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel client = server.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                    System.out.println("Connected to client: " + client.getRemoteAddress());
                }
                // Handle other operations like OP_READ, OP_WRITE
            }
            selector.selectedKeys().clear();
        }
    }
}

4.2 异步编程模型

Java的 CompletableFuture 提供了强大的异步编程支持。通过 CompletableFuture,你可以在非阻塞的情况下处理异步任务。

import java.util.concurrent.CompletableFuture;

public class CompletableFutureExample {
    public static void main(String[] args) {
        CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep

(2000); // 模拟长时间操作
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Result after 2 seconds";
        }).thenAccept(result -> {
            System.out.println("Received: " + result);
        });

        System.out.println("Main thread continues...");
    }
}

在这个例子中,异步任务在后台运行,主线程不必等待它完成,可以继续执行其他操作。

5. 总结

阻塞式方法是Java编程中处理线程同步、I/O操作和网络通信的常见方式。虽然它们易于使用,但在高并发和性能要求高的应用中,阻塞式方法可能会导致性能瓶颈。因此,开发者需要根据具体的应用场景,权衡使用阻塞式方法与非阻塞式方法或异步编程模型。

  • 阻塞式方法的优点:简单易用,适合处理顺序执行的任务。
  • 阻塞式方法的缺点:在高并发或实时性要求高的系统中可能导致性能问题。
  • 非阻塞与异步替代方案:Java NIO和 CompletableFuture 提供了更高效的解决方案,适用于需要处理大量并发任务的场景。

通过理解阻塞式方法的工作原理及其适用场景,开发者可以更好地设计和优化Java应用程序,满足不同场景下的性能需求。

到此这篇关于java实现线程阻塞式方法的文章就介绍到这了,更多相关java 线程阻塞内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot通过注解监测Controller接口的代码示例

    SpringBoot通过注解监测Controller接口的代码示例

    在Spring Boot中,度量指标(Metrics)是监控和诊断应用性能与行为的重要工具,Spring Boot通过集成Micrometer和Spring Boot Actuator,提供了强大的度量指标收集与暴露功能,本文介绍了SpringBoot通过注解监测Controller接口,需要的朋友可以参考下
    2024-07-07
  • Spring中AOP概念与两种动态代理模式原理详解

    Spring中AOP概念与两种动态代理模式原理详解

    AOP是面向切面编程的技术,AOP基于IoC基础,是对OOP的有益补充,流行的AOP框架有Sping AOP、AspectJ,这篇文章主要给大家介绍了关于Spring中AOP概念与两种动态代理模式原理的相关资料,需要的朋友可以参考下
    2021-10-10
  • Springboot-Shiro基本使用详情介绍

    Springboot-Shiro基本使用详情介绍

    这篇文章主要介绍了Springboot-Shiro基本使用详情,文章根据官网依据官网快速搭建Quickstart,配置pom.xml依赖等操作,需要的小伙伴可以参考下面文章内容
    2022-01-01
  • Java字符串编码解码性能提升的技巧分享

    Java字符串编码解码性能提升的技巧分享

    这篇文章主要是和大家分享几个Java中提升字符串编码解码性能的小技巧,文中的示例代码讲解详细,对我们学习有一定的帮助,需要的可以参考一下
    2022-05-05
  • SpringBoot构建企业级RESTful API项目的完整指南

    SpringBoot构建企业级RESTful API项目的完整指南

    在现代软件开发中,RESTful API已成为构建分布式系统和微服务架构的标准方式,本指南将带大家从零开始,使用Spring Boot构建一个完整的企业级RESTful API项目
    2025-07-07
  • java如何实现socket连接方法封装

    java如何实现socket连接方法封装

    这篇文章主要介绍了java实现socket连接方法封装教程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Java中类的定义和初始化示例详解

    Java中类的定义和初始化示例详解

    这篇文章主要给大家介绍了关于Java中类的定义和初始化的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Nacos框架与原理之Nacos的参数

    Nacos框架与原理之Nacos的参数

    这篇文章主要介绍了Nacos框架与原理之Nacos的参数,Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护阈值、服务路由类型、临时实例等,但下面文章我们要讲解的是参数,参数是什么呢,下面一起进去文章学习详细内容吧
    2022-05-05
  • 详解使用spring boot admin监控spring cloud应用程序

    详解使用spring boot admin监控spring cloud应用程序

    本篇文章主要介绍了详解使用spring boot admin监控spring cloud应用程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • java 如何往已经存在的excel表格里面追加数据的方法

    java 如何往已经存在的excel表格里面追加数据的方法

    这篇文章主要介绍了java 如何往已经存在的excel表格里面追加数据的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08

最新评论