切记【阻塞/非阻塞】【FutureTask异步执行】

73 篇文章 8 订阅

一、阻塞非阻塞

1.1 同步阻塞IO

在Java应用中,默认情况下所有的Socket连接的IO都是同步阻塞的
例如在java发起的一个socket的read操作大致流程如下:
1.Java启动io的read读操作开始,用户线程就进入阻塞状态
2.系统接收到read调用,开始准备数据,如果内核数据没有准备好,则内核进行等待。
3.内核一直等待完整的数据到达,就会将数据从内核缓冲区复制到用户缓冲区,返回内核结果.
4.内核返会结果后,用户线程才会解除阻塞的状态,重新运行。
特点:在内核执行IO两个点阶段,用户线程都被阻塞了。
优点:开发程序简单,阻塞期间,用户线程不占用CPU。
缺点:每个连接配备独立的线程,高并发场景下,需要大量的线程维护网络连接,内存,线程切换开销会非常大。

1.2 同步非阻塞NIO

1.内核中没有数据,系统会直接返回调用失败的结果,用户线程需要不断地发起IO调用。
2.内核中有数据,发生阻塞,知道数据从内核中复制到用户线程中,复制完成后,系统调用返回成功,解除阻塞状态,用户空间进行处理。
特点:用户线程需要不断的轮询IO系统调用,轮询数据是否已经准备好。
优点:每次发起IO调用,可以立马反悔一个结果,用户线程不会阻塞,实时性较好。
缺点:不断轮询,占用CPU,效率低下。

二、同步、异步

同步方法调用一旦开始,调用者必须等到方法调用返回后,才能继续后续的行为。
异步方法调用更像一个消息传递,一旦开始,方法调用就会立即返回,调用者就可以继续后续的操作。而,异步方法通常会在另外一个线程中,“真实”地执行着。整个过程,不会阻碍调用者的工作.

三、FutureTask结合Callable接口创建线程【异步】

Future是JDK用于处理多线程环境下异步问题的一种模式,FutureTask就是Future的一种实现。
他最大的好处就是:客户端发出请求后,可以立马得到一个返回结果,而不用一直等待这服务器来处理。
在Callable接口中,call()方法有一个类型的泛型返回值,返回值可以是任意类型,就可以通过FutureTask的get()方法来接受返回值。get方法是一个闭锁式的阻塞方法,此方法会一直等待,知道call方法执行完毕return返回值为止。

例如:Callable创建线程计算 1-100之和并返回个Main线程的sum变量:

public class CallableTest {
    public static void main(String[] args) {

        MyCallableThread thread = new MyCallableThread();
        FutureTask<Integer> task = new FutureTask<>(thread);
        new Thread(task).start();

        try {
            Integer sum = task.get();
            System.out.println(sum);
        }catch (Exception e){
        }
    }
}

class MyCallableThread implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("线程开始计算 1 + ... +100");
        int sum = 0;
        for (int i = 1; i <=100; i++) {
            sum =sum + i;
        }
        return sum;
    }
}
Java中,可以使用FutureTask类来等待异步执行结果。具体步骤如下: 1. 定义一个Callable接口的实现类,用于执行需要获取结果集的操作,并返回结果。 2. 创建一个FutureTask对象,将Callable实现类实例作为参数传递给FutureTask构造函数。 3. 使用Executor框架(例如ThreadPoolExecutor)来执行FutureTask对象,异步执行操作并返回Future对象。 4. 在主线程中,使用Future.get()方法获取异步操作的结果。该方法会阻塞当前线程,直到异步操作完成并返回结果。 下面是一个简单的示例代码: ```java import java.util.concurrent.*; public class FutureTaskExample { public static void main(String[] args) throws Exception { // 创建一个Callable实现类的实例 Callable<Integer> task = new Callable<Integer>() { public Integer call() { // 模拟异步操作 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return 100; } }; // 创建FutureTask对象,将Callable实现类实例作为参数传递给FutureTask构造函数 FutureTask<Integer> futureTask = new FutureTask<Integer>(task); // 创建线程池并执行FutureTask对象 Executor executor = Executors.newSingleThreadExecutor(); executor.execute(futureTask); // 在主线程中,使用Future.get()方法获取异步操作的结果 Integer result = futureTask.get(); System.out.println("异步操作的结果是:" + result); } } ``` 在上面的示例代码中,创建了一个Callable实现类的实例,并将其传递给FutureTask构造函数。然后,通过线程池异步执行FutureTask对象,并在主线程中使用Future.get()方法获取异步操作的结果。注意,Future.get()方法会阻塞当前线程,直到异步操作完成并返回结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Coding路人王

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

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

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

打赏作者

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

抵扣说明:

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

余额充值