万字长文!用代码实例带你彻底:精通CompletableFuture的使用

2023-05-16

前言

创建线程的方式只有两种:继承Thread或者实现Runnable接口。 但是这两种方法都存在一个缺陷,没有返回值

Java 1.5 以后,可以通过向线程池提交一个Callable来获取一个包含返回值的Future对象

Future接口的局限性

当Future的线程进行了一个非常耗时的操作,那我们的主线程也就阻塞了。

当我们在简单业务上,可以使用Future的另一个重载方法get(long,TimeUnit)来设置超时时间,避免我们的主线程被无穷尽地阻塞。

单纯使用Future接口或者FutureTask类并不能很好地完成以下我们所需的业务

  • 将两个异步计算合并为一个,这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果
  • 等待Future集合中的所有任务都完成。
  • 仅等待Future集合种最快结束的任务完成,并返回它的结果。
  • 通过编程方式完成一个Future任务的执行
  • 当Future的完成时间完成时会收到通知,并能使用Future的计算结果进行下一步的的操作,不只是简单地阻塞等待操作的结果

什么是CompletableFuture

在Java 8中, 新增类: CompletableFuture,结合了Future的优点,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果

CompletableFuture被设计在Java中进行异步编程。主线程不用为了任务的完成而阻塞/等待,你可以用主线程去并行执行其他的任务。 使用这种并行方式,极大地提升了程序的表现。

  • CompletableFuture实现了Future接口,因此有异步执行返回结果的能力。
  • CompletableFuture实现了CompletionStage接口,该接口是Java8新增得一个接口,用于异步执行中的阶段处理,其大量用在Lambda表达式计算过程中,目前只有CompletableFuture一个实现类。
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

方法命名规则

  • 带有Async后缀方法都是异步另外线程执行,没有就是复用之前任务的线程
  • 带有Apply标识方法都是可以获取返回值+有返回值的
  • 带有Accept标识方法都是可以获取返回值
  • 带有run标识的方法不可以获取返回值和无返回值,只是运行

get方法和join方法

  • join:阻塞获取结果或抛出非受检异常。
  • get: 阻塞获取结果或抛出受检测异常,需要显示进行try...catch处理

不同线程池使用

默认线程池执行

/**
 * 默认线程池
 * 运行结果:
 * main.................start.....
 * main.................end......
 * 当前线程:ForkJoinPool.commonPool-worker-9
 * 运行结果:5
 */
@Test
public void defaultThread() {
    System.out.println("main.................start.....");
    CompletableFuture.runAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getName());
        int i = 10 / 2;
        System.out.println("运行结果:" + i);
    });
    System.out.println("main.................end......");
}

默认使用 ForkJoinPool.commonPool(),commonPool是一个会被很多任务共享的线程池,commonPool 设计时的目标场景是运行 非阻塞的 CPU 密集型任务,为最大化利用 CPU,其线程数默认为 CPU 数量- 1

  • 哪些地方使用了commonPool
    • CompletableFuture
    • Parallel Streams
  • 为什么要引入commonPool
    • 为了避免任何并行操作都引入一个线程池,最坏情况会导致在单个JVM上创建了太多的池线程,降低效率。
  • commonPool线程池是怎么创建和使用的
    • ForkJoinTask一定会运行在一个ForkJoinPool中,如果没有显式地交它提交到ForkJoinPool,会使用一个common池(全进程共享)来执行任务。

自定义线程池执行

自定义一个线程池

private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>());

使用定义的线程池

/**
 * 自定义线程池
 * 运行结果:
 * main.................start.....
 * main.................end......
 * 当前线程:pool-1-thread-1
 * 运行结果:5
 */
@Test
public void myThread() {
    System.out.println("main.................start.....");
    CompletableFuture.runAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getName());
        int i = 10 / 2;
        System.out.println("运行结果:" + i);
    },executor);
    System.out.println("main.................end......");
}

开启一个异步

runAsync-无返回值

使用runAsync开启一个异步任务线程,该方法无结果返回,适合一些不需要结果的异步任务

/***
 * 无返回值
 *  runAsync
 *  结果:
 * main.................start.....
 * main.................end......
 * 当前线程:33
 * 运行结果:5
 */
@Test
public void runAsync() {
    System.out.println("main.................start.....");
    CompletableFuture.runAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("运行结果:" + i);
    }, executor);
    System.out.println("main.................end......");
}

supplyAsync-有返回值

使用completableFuture.get()方法获取结果,这时程序会阻塞到这里直到结果返回。

/**
 * 有返回值
 * supplyAsync
 * 结果:
 * main.................start.....
 * 当前线程:33
 * 运行结果:5
 * main.................end.....5
 */
@Test
public void supplyAsync() throws ExecutionException, InterruptedException {
    System.out.println("main.................start.....");
    CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("运行结果:" + i);
        return i;
    }, executor);
    System.out.println("main.................end....." + completableFuture.get());
}

如果要超时就得往下执行,请使用completableFuture.get(long timeout, TimeUnit unit)方法。

线程串行化方法

带有Async后缀方法都是异步另外线程执行,没有就是复用之前任务的线程

thenApply-上面任务执行完执行+获取返回值+有返回值

/**
 * 上面任务执行完执行+可以拿到结果+可以返回值
 * 结果:
 * thenApplyAsync当前线程:33
 * thenApplyAsync运行结果:5
 * thenApplyAsync任务2启动了。。。。。上步结果:5
 * main.................end.....hello10
 * 
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void thenApplyAsync() throws ExecutionException, InterruptedException {

    CompletableFuture<String> thenApplyAsync = CompletableFuture.supplyAsync(() -> {
        System.out.println("thenApplyAsync当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("thenApplyAsync运行结果:" + i);
        return i;
    }, executor).thenApplyAsync(result -> {
        System.out.println("thenApplyAsync任务2启动了。。。。。上步结果:" + result);
        return "hello" + result * 2;
    }, executor);
    System.out.println("main.................end....." + thenApplyAsync.get());
}

thenAccept-上面任务执行完执行+获取返回值

/**
 * 上面任务执行完执行+可以拿到结果
 * 结果:
 * thenAcceptAsync当前线程:33
 * thenAcceptAsync运行结果:5
 * thenAcceptAsync任务2启动了。。。。。上步结果:5
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void thenAcceptAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Void> thenAcceptAsync = CompletableFuture.supplyAsync(() -> {
        System.out.println("thenAcceptAsync当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("thenAcceptAsync运行结果:" + i);
        return i;
    }, executor).thenAcceptAsync(result -> {
        System.out.println("thenAcceptAsync任务2启动了。。。。。上步结果:" + result);
    }, executor);
}

thenRun-上面任务执行完执行

/**
 * 上面任务执行完执行
 * 结果
 * main.................start.....
 * 当前线程:33
 * 运行结果:5
 * 任务2启动了。。。。。
 */
@Test
public void thenRunAsync() throws ExecutionException, InterruptedException {
    System.out.println("main.................start.....");
    CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("运行结果:" + i);
        return i;
    }, executor).thenRunAsync(() -> {
        System.out.println("任务2启动了。。。。。");
    }, executor);
}

thenCompose-接收返回值并生成新的任务

当原任务完成后接收返回值,返回一个新的任务

  • thenApply()转换的是泛型中的类型,相当于将CompletableFuture 转换生成新的CompletableFuture
  • thenCompose()用来连接两个CompletableFuture,是生成一个新的CompletableFuture。
/**
 * 当原任务完成后接收返回值,返回一个新的任务
 * 结果:
 * hello: thenCompose
 */
@Test
public void thenCompose() {
    CompletableFuture cf = CompletableFuture.completedFuture("hello")
            .thenCompose(str -> CompletableFuture.supplyAsync(() -> {
                return str + ": thenCompose";
            },executor));
    System.out.println(cf.join());
}

任务组合

thenCombine-消费两个结果+返回结果

/**
 * 两任务组合 都要完成
 * completableFuture.thenCombine()获取两个future返回结果,有返回值
 * 结果:
 * 任务1线程:33
 * 任务1运行结果:5
 * 任务2线程:34
 * 任务2运行结果:
 * 任务5启动。。。结果1:5。。。结果2:hello
 * 任务5结果hello-->5
 */
@Test
public void thenCombine() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("任务1运行结果:" + i);
        return i;
    }, executor);

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);
    CompletableFuture<String> thenCombineAsync = future1.thenCombineAsync(future2, (result1, result2) -> {
        System.out.println("任务5启动。。。结果1:" + result1 + "。。。结果2:" + result2);
        return result2 + "-->" + result1;
    }, executor);
    System.out.println("任务5结果" + thenCombineAsync.get());
}

thenAcceptBoth-消费两个结果+无返回

/**
 * 两任务组合 都要完成
 * completableFuture.thenAcceptBoth() 获取两个future返回结果,无返回值
 * 结果:
 * 任务1线程:33
 * 任务1运行结果:5
 * 任务2线程:34
 * 任务2运行结果:
 * 任务4启动。。。结果1:5。。。结果2:hello
 */
@Test
public void thenAcceptBothAsync() throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("任务1运行结果:" + i);
        return i;
    }, executor);

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);

    CompletableFuture<Void> thenAcceptBothAsync = future1.thenAcceptBothAsync(future2, (result1, result2) -> {
        System.out.println("任务4启动。。。结果1:" + result1 + "。。。结果2:" + result2);
    }, executor);

}

runAfterBoth-两个任务完成接着运行

/**
 * 两任务组合 都要完成
 * completableFuture.runAfterBoth() 组合两个future
 * 结果:
 * 任务1线程:33
 * 任务1运行结果:5
 * 任务2线程:34
 * 任务2运行结果:
 * 任务3启动。。。
 */
@Test
public void runAfterBothAsync() {
    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        System.out.println("任务1运行结果:" + i);
        return i;
    }, executor);

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);

    CompletableFuture<Void> runAfterBothAsync = future1.runAfterBothAsync(future2, () -> {
        System.out.println("任务3启动。。。");
    }, executor);

}

两任务完成一个就执行

applyToEither-其中一个执行完执行+获取返回值+有返回值

/**
 * 两任务组合,一个任务完成就执行
 * objectCompletableFuture.applyToEither() 其中一个执行完执行+获取返回值+有返回值
 * 结果:
 * 任务1线程:33
 * 任务2线程:34
 * 任务2运行结果:
 * 任务5开始执行。。。结果:hello
 * 任务5结果:hello world
 * <p>
 * Process finished with exit code 0
 */
@Test
public void applyToEither() throws ExecutionException, InterruptedException {
    CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        try {
            Thread.sleep(3000);
            System.out.println("任务1运行结果:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }, executor);

    CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);

    CompletableFuture<String> applyToEitherAsync = future1.applyToEitherAsync(future2, result -> {
        System.out.println("任务5开始执行。。。结果:" + result);
        return result.toString() + " world";
    }, executor);
    System.out.println("任务5结果:" + applyToEitherAsync.get());
}

acceptEither-其中一个执行完执行+获取返回值

/**
 * 两任务组合,一个任务完成就执行
 * objectCompletableFuture.acceptEither() 其中一个执行完执行+获取返回值
 * 结果:
 * 任务1线程:33
 * 任务2线程:34
 * 任务2运行结果:
 * 任务4开始执行。。。结果:hello
 */
@Test
public void acceptEither() {
    CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        try {
            Thread.sleep(3000);
            System.out.println("任务1运行结果:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }, executor);

    CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);

    CompletableFuture<Void> acceptEitherAsync = future1.acceptEitherAsync(future2, result -> {
        System.out.println("任务4开始执行。。。结果:" + result);
    }, executor);

}

runAfterEither-有一任务完成就执行

/**
 * 两任务组合,一个任务完成就执行
 * <p>
 * objectCompletableFuture.runAfterEither() 其中一个执行完执行
 * 结果:
 * 任务1线程:33
 * 任务2线程:34
 * 任务2运行结果:
 * 任务3开始执行。。。
 */
@Test
public void runAfterEither() {
    CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1线程:" + Thread.currentThread().getId());
        int i = 10 / 2;
        try {
            Thread.sleep(3000);
            System.out.println("任务1运行结果:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return i;
    }, executor);

    CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务2线程:" + Thread.currentThread().getId());
        System.out.println("任务2运行结果:");
        return "hello";
    }, executor);

    CompletableFuture<Void> runAfterEitherAsync = future1.runAfterEitherAsync(future2, () -> {
        System.out.println("任务3开始执行。。。");
    }, executor);
}

多任务组合

allOf-等待全部完成后才执行

/**
 * 多任务组合
 * allOf 等待所有任务完成
 * 结果:
 * 任务1
 * 任务3
 * 任务2
 * allOf任务1-------任务2-------任务3
 *
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void allOf() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1");
        return "任务1";
    }, executor);
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);
            System.out.println("任务2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "任务2";
    }, executor);
    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务3");
        return "任务3";
    }, executor);

    CompletableFuture<Void> allOf = CompletableFuture.allOf(future1, future2, future3);
    //等待所有任务完成
    //allOf.get();
    allOf.join();
    System.out.println("allOf" + future1.get() + "-------" + future2.get() + "-------" + future3.get());

}

anyOf-等待其中之一完成后就执行


/**
 * 多任务组合
 * anyOf 只要一个任务完成
 * 结果:
 * 任务1
 * anyOf--最先完成的是任务1
 * 任务3
 * 等等任务2
 * 任务2
 *
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void anyOf() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务1");
        return "任务1";
    }, executor);
    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000);
            System.out.println("任务2");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "任务2";
    }, executor);

    CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
        System.out.println("任务3");
        return "任务3";
    }, executor);
    CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future1, future2, future3);
    System.out.println("anyOf--最先完成的是" + anyOf.get());
    //等待future2打印
    System.out.println("等等任务2");
    Thread.sleep(3000);
}

感知异常

handle-捕获结果或异常并返回新结果

入参为结果或者异常,返回新结果

/**
 * 入参为结果或者异常,返回新结果
 * 结果:
 * main.................start.....
 * 当前线程:33
 * main.................end.....报错返回
 */
@Test
public void handle() throws ExecutionException, InterruptedException {
    System.out.println("main.................start.....");
    final CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 0;
        System.out.println("运行结果:" + i);
        return i;
    }, executor).handleAsync((in, throwable) -> {
        if (throwable != null) {
            return "报错返回";
        }
        return "正确了";
    });
    System.out.println("main.................end....." + completableFuture.get());

}

whenComplete-感知结果或异常并返回相应信息

whenComplete虽然得到异常信息,但是不能修改返回信息

/**
 * 有返回值并且有后续操作 whenComplete
 * <p>
 * 结果:
 * main.................start.....
 * 当前线程:33
 * 异步完成。。。。结果是:null...异常是:java.util.concurrent.CompletionException: java.lang.ArithmeticException: 除以零
 * 报错了2
 *
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void whenComplete() {
    System.out.println("main.................start.....");
    final CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 0;
        System.out.println("运行结果:" + i);
        return i;
    }, executor).whenComplete((result, throwable) -> {
        //whenComplete虽然得到异常信息,但是不能修改返回信息
        System.out.println("异步完成。。。。结果是:" + result + "...异常是:" + throwable);
    });

    try {
        System.out.println("main.................end..T..." + completableFuture.get());
    } catch (InterruptedException e) {
        System.out.println("报错了1");
    } catch (ExecutionException e) {
        System.out.println("报错了2");
    }
}

exceptionally-捕获异常并返回指定值

/**
 * 方法完成后的感知
 * 感知错误并返回指定值 exceptionally
 * 结果:
 * main.................start.....
 * 当前线程:33
 * 执行了exceptionally
 * main.................end.....0
 * @throws ExecutionException
 * @throws InterruptedException
 */
@Test
public void exceptionally() throws ExecutionException, InterruptedException {
    System.out.println("main.................start.....");
    CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("当前线程:" + Thread.currentThread().getId());
        int i = 10 / 0;
        System.out.println("运行结果:" + i);
        return i;
    }, executor).exceptionally(throwable -> {
        //R apply(T t);
        //exceptionally可以感知错误并返回指定值
        System.out.println("执行了exceptionally");
        return 0;
    });
    System.out.println("main.................end....." + completableFuture.get());
}

本文给大家讲解的内容是CompletableFuture的使用详解

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

万字长文!用代码实例带你彻底:精通CompletableFuture的使用 的相关文章

  • 我的首篇博客——记录学习,不忘初心

    Hello 大家好 xff01 我是阿冰 xff01 今天是2022年12月2日 xff0c 受疫情影响 xff0c 我们学校的同学都早早的回家了 xff0c 今天就是我回家的第五天 其实 xff0c 这并不算是真正意义的寒假 xff0c
  • Java标识符和关键字

    目录 前言 一 关键字 1 什么是关键字 xff1f 2 关键字的一些注意事项 二 标识符 1 什么是标识符 xff1f 2 标识符书写规范 总结 前言 在华清学习的所思所想 xff1a Java关键字及标识符 一 关键字 1 什么是关键字
  • 图为科技NVIDIA Jetson Xavier NX测评

    NVIDIA推出了世界上最小的人工智能计算机 NVIDIA Jetson Xavier NX 整个设置的大小小于普通大小的借记卡或信用卡 该模块虽然不是业务中最小的 xff0c 但它所提供的处理能力和其他质量足以弥补其尺寸 Jetson N
  • Jetson TX2 NX 模块以纳米尺寸提供 TX2 电源

    Nvidia 推出了Jetson TX2计算模块 的降速功能 xff0c 该模块位于 TX2 和低端Jetson Nano之间 Jetson TX2 NX 在与 TX2 相同的六核 CPU 和 256 核 Pascal GPU 上运行 Li
  • 无人机在行业的应用方面呈现出多元化的趋势

    随着科技的不断发展和进步 xff0c 无人机的行业应用也逐渐扩大 作为民用无人机主要细分领域之一 xff0c 测绘无人机的发展也越来越成熟 xff0c 市场规模保持高速增长 无人机在应用方面也呈现出多元化的趋势 xff0c 备受各个行业用户
  • 嵌入式能从事什么职业?

    嵌入式本身发展是很好的 xff0c 这也是大家接触它的原因 xff0c 最后大家也是想通过学习嵌入式而找到关于嵌入式开发的工作 xff0c 想必大家也应该知道嵌入式工作要求有很多 xff0c 下面就一起来看看嵌入式能从事什么职业吧 点击获取
  • 嵌入式入门学习的必要步骤

    很多新手在入门嵌入式的时候 xff0c 经常会有很多问题 xff0c 这也都是想要多多去了解嵌入式 xff0c 也害怕自己浪费了时间还没有学会嵌入式 xff0c 掌握到好方法学习嵌入式 xff0c 那么就会事半功倍 xff0c 下面一起来看
  • 逆变器原理

    逆变器是把直流电转变为交流电的一种装置 它一般包括逆变桥 控制逻辑和滤波电路组成 主要是把各种直流源转变为交流供交流负载使用 xff0c 一般直流源有蓄电池 干电池 太阳能电池等 xff0c 可以应用到不间断电源 UPS 太阳能发电转换等
  • RS-485 通讯协议简介

    与 CAN 类似 xff0c RS 485 是一种工业控制环境中常用的通讯协议 xff0c 它具有抗干扰能力强 传输距离远的特点 RS 485 通讯协议由 RS 232协议改进而来 xff0c 协议层不变 xff0c 只是改进了物理层 xf
  • 反向散射耦合RFID系统的原理及特点,带你更深入的了解

    一 反向散射耦合RFID系统 1 反向散射 雷达技术为RFID的反向散射耦合方式提供了理论和应用基础 当电磁波遇到空间目标时 xff0c 其能量的一部分被目标吸收 xff0c 另一部分以不同的强度散射到各个方向 在散射的能量中 xff0c
  • 西门子PLC,1200PLC如何接线,2分钟就能明白

    西门子PLC xff0c 1200PLC如何接线 xff0c 2分钟就能明白 西门子PLC xff0c 1200PLC如何接线 xff0c 2分钟就能明白 哔哩哔哩 bilibili
  • 2022年嵌入式开发就业前景怎么样?

    时间 xff1a 2022年5月26号 xff01 这几年嵌入式开发的发展前景可以说是非常的香 xff01 从工资和找工作的难易程度上说都是 xff01 按老师傅的说法就是 xff1a 加班不严重 xff0c 注重积累 xff0c 越往底层
  • ARM结构体系3:ARM指令的寻址和异常中断处理

    目录 ARM处理器的八种寻址方式 1 立即数寻址 2 寄存器寻址 3 寄存器间接寻址 4 寄存器移位寻址 5 基址变址寻址 6 多寄存器寻址 7 相对寻址 8 堆栈寻址 9 GNU汇编伪指令 异常中断处理 1 7种异常源 2 异常向量表 A
  • 51单片机(ESP8266模块)

    前言 xff1a 蓝牙 xff0c ESP 01s xff0c Zigbee NB Iot等通信模块都是基于AT指令的设计 一 AT指令 AT指令集是从终端设备 xff08 Terminal Equipment xff0c TE 或数据终端
  • 嵌入式工作机会会越来越少吗

    我认为嵌入式工作会越来越多 在当前产业结构升级的大背景下 xff0c 物联网会与诸多的行业领域产生更加紧密的联系 xff0c 而这个过程必然离不开嵌入式开发的参与 应用场景对于嵌入式开发领域的发展有非常直接的影响 xff0c 嵌入式开发要想
  • 大学生为何很想往嵌入式方向发展?

    这几年嵌入式工资一直在再涨 xff0c 挺好的 xff01 可以选择的公司也比较多 xff0c 起薪差不读在10k 13k的样子 招聘公司统计的数据是19K 优点1 xff1a 应届生嵌入式行业的薪资在毕业生眼里看来真的是很香 xff0c
  • 涨姿势 | 一文说透电机控制器硬件在环测试(MCU HIL)

    软件质量是嵌入式产品开发中最关注的问题之一 随着产品迭代 xff0c 软件复杂程度越来越高 xff0c 为保证软件质量 xff0c 需要对软件进行大量的测试 xff0c 这会在整个产品周期中消耗大量时间及资源 另一方面 xff0c 市场竞争
  • VMware Workstation创建Windows 11(21H2)虚拟机

    2021年6月24日 xff0c 微软发布了Windows 11 xff0c 很多人都想 尝尝鲜 可以为较高的电脑配置 xff0c 使得很多老电脑 望而却步 xff0c 或者有人想换可又嫌麻烦或不舍得 所以今天我来带大家创建Windows
  • 计算机知识——常见的存储类型

    一 常见存储器类型 xff1a 1 易失 非易失性存储器 xff1a 是指存储器断电后 xff0c 它存储的数据内容是否会丢失的特性 由于一般易失性存储器存取速度快 xff0c 而非易失性存储器可长期保存数据 易失性存储器最典型的代表是内存
  • 使用select函数实现TCP并发服务器

    首先介绍一下select 函数的功能 参数 返回值 int select int nfds fd set readfds fd set writefds fd set exceptfds struct timeval timeout voi

随机推荐