Java中使用到的异步任务总结(CompletableFuture类,@Async注解)

2023-10-27

1.CompletableFuture

1.1 Completable.supplyAsync

代码示例:

@Slf4j
public class FutureDemo {
    public static void main(String[] args) {
        System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
            System.out.println(getTime() + " 开始执行异步任务");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getTime() + " 异步任务3秒执行完成");
            return "异步任务执行结果";
        });
        System.out.println(getTime() + " 主线程执行任务中");
        String s = null;
        try {
            s = completableFuture.get(4, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            log.warn(getTime() + " 执行异步任务超时");
            //可以选择返回继续执行后面的或者抛异常终止
            return;
//            throw new RuntimeException(e);
        }
        System.out.println(getTime() + " " + s);
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }
}

输出:
2023-04-17 04:33:09 当前线程:main
2023-04-17 04:33:09 主线程执行任务中
2023-04-17 04:33:09 当前线程:ForkJoinPool.commonPool-worker-1
2023-04-17 04:33:09 开始执行异步任务
2023-04-17 04:33:12 异步任务3秒执行完成
2023-04-17 04:33:12 异步任务执行结果

简单分析一下,Completable使用的是ForkJoinPool线程池,Completable.supplyAsync方法返回异步执行结果,通过get方法获取,可以设置超时时间;

1.2 Completable.runAsync

代码示例

    public static void main(String[] args) {
        System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
            System.out.println(getTime() + " 开始执行异步任务");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getTime() + " 异步任务3秒执行完成");
        });
        System.out.println(getTime() + " 主线程执行任务中");
        try {
            Void task = completableFuture.get(5, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            log.warn(getTime() + " 执行异步任务超时");
            //可以选择返回继续执行后面的或者抛异常终止
            return;
//            throw new RuntimeException(e);
        }
        System.out.println(getTime() + " over");
    }

输出:
2023-04-17 05:37:38 当前线程:main
2023-04-17 05:37:38 主线程执行任务中
2023-04-17 05:37:38 当前线程:ForkJoinPool.commonPool-worker-1
2023-04-17 05:37:38 开始执行异步任务
2023-04-17 05:37:41 异步任务3秒执行完成
2023-04-17 05:37:41 over

1.3 get方法

和supplyAsync不同的是没有返回值,有一个需要注意的点,不管是Completable.supplyAsync还是Completable.runAsync方法,如果没有调用get方法的话,异步任务可能不会执行完,尝试讲get方法注释得到下面的输出结果:

2023-04-17 05:39:48 当前线程:main
2023-04-17 05:39:48 主线程执行任务中
2023-04-17 05:39:48 over
2023-04-17 05:39:48 当前线程:ForkJoinPool.commonPool-worker-1
2023-04-17 05:39:48 开始执行异步任务

get方法会阻塞主线程,等待异步执行完成;

1.4 使用自定义线程池

或者通过自定义线程池的方式,Completable使用默认的线程池创建的线程是守护线程,守护线程会随着主线程的结束而结束,而使用自己创建的线程池,不是守护线程,所以主线程结束之后,可以继续执行;

    public static void main(String[] args) {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName());
            System.out.println(getTime() + " 开始执行异步任务");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getTime() + " 异步任务3秒执行完成");
        }, executorService);
        System.out.println(getTime() + " 主线程执行任务中");
//        try {
//            Void task = completableFuture.get(5, TimeUnit.SECONDS);
//        } catch (InterruptedException | ExecutionException | TimeoutException e) {
//            log.warn(getTime() + " 执行异步任务超时");
//            //可以选择返回继续执行后面的或者抛异常终止
//            return;
            throw new RuntimeException(e);
//        }
        System.out.println(getTime() + " over");
    }

输出:
2023-04-17 05:56:45 当前线程:main
2023-04-17 05:56:45 主线程执行任务中
2023-04-17 05:56:45 over
2023-04-17 05:56:45 当前线程:service-thread-0
2023-04-17 05:56:45 开始执行异步任务
2023-04-17 05:56:48 异步任务3秒执行完成

1.5 Completable.allof示例 等待异步线程执行统一返回

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //定义线程池
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        //预准备数据
        List<Integer> lists = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            lists.add(i);
        }
        //数据转换格式
        Function<Integer, CompletableFuture<String>> function = item -> CompletableFuture.supplyAsync(() -> {
            System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName() + " " + item.toString());
            return item.toString();
        }, executorService);
        //进行数据转换
        List<CompletableFuture<String>> list1 = lists.stream().map(function).collect(Collectors.toList());
        //等待所有异步线程返回
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(list1.toArray(new CompletableFuture[0]));
        //这里会阻塞主线程
        voidCompletableFuture.get(2, TimeUnit.SECONDS);
        list1.stream().map(i -> {
            try {
                String s = i.get();
                System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName() + " " + s + " over");
                return s;
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
        executorService.shutdownNow();
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }
}

输出
2023-04-18 02:14:16 当前线程:service-thread-0 0
2023-04-18 02:14:16 当前线程:service-thread-2 2
2023-04-18 02:14:16 当前线程:service-thread-1 1
2023-04-18 02:14:16 当前线程:service-thread-0 3
2023-04-18 02:14:16 当前线程:service-thread-2 4
2023-04-18 02:14:16 当前线程:service-thread-0 6
2023-04-18 02:14:16 当前线程:service-thread-2 7
2023-04-18 02:14:16 当前线程:service-thread-0 8
2023-04-18 02:14:16 当前线程:service-thread-2 9
2023-04-18 02:14:16 当前线程:service-thread-1 5
2023-04-18 02:14:16 当前线程:main 0 over
2023-04-18 02:14:16 当前线程:main 1 over
2023-04-18 02:14:16 当前线程:main 2 over
2023-04-18 02:14:16 当前线程:main 3 over
2023-04-18 02:14:16 当前线程:main 4 over
2023-04-18 02:14:16 当前线程:main 5 over
2023-04-18 02:14:16 当前线程:main 6 over
2023-04-18 02:14:16 当前线程:main 7 over
2023-04-18 02:14:16 当前线程:main 8 over
2023-04-18 02:14:16 当前线程:main 9 over

如果不对主线程进行阻塞

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //定义线程池
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        //预准备数据
        List<Integer> lists = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            lists.add(i);
        }
        //数据转换格式
        Function<Integer, CompletableFuture<String>> function = item -> CompletableFuture.supplyAsync(() -> {
            System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName() + " " + item.toString());
            try {
                //进行睡眠
                Thread.sleep(item * 1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return item.toString();
        }, executorService);
        //进行数据转换
        List<CompletableFuture<String>> list1 = lists.stream().map(function).collect(Collectors.toList());
        //等待所有异步线程返回
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(list1.toArray(new CompletableFuture[0]));
        //这里会阻塞主线程
//        voidCompletableFuture.get(2, TimeUnit.SECONDS);
        list1.stream().map(i -> {
            try {
                String s = i.get();
                System.out.println(getTime() + " 当前线程:" + Thread.currentThread().getName() + " " + s + " over");
                return s;
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
        executorService.shutdownNow();
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }
}

输出
2023-04-18 02:47:15 当前线程:service-thread-0 0
2023-04-18 02:47:15 当前线程:service-thread-1 1
2023-04-18 02:47:15 当前线程:service-thread-2 2
2023-04-18 02:47:15 当前线程:service-thread-0 3
2023-04-18 02:47:15 当前线程:main 0 over
2023-04-18 02:47:16 当前线程:main 1 over
2023-04-18 02:47:16 当前线程:service-thread-1 4
2023-04-18 02:47:17 当前线程:service-thread-2 5
2023-04-18 02:47:17 当前线程:main 2 over
2023-04-18 02:47:18 当前线程:main 3 over
2023-04-18 02:47:18 当前线程:service-thread-0 6
2023-04-18 02:47:20 当前线程:main 4 over
2023-04-18 02:47:20 当前线程:service-thread-1 7
2023-04-18 02:47:22 当前线程:main 5 over
2023-04-18 02:47:22 当前线程:service-thread-2 8
2023-04-18 02:47:24 当前线程:service-thread-0 9
2023-04-18 02:47:24 当前线程:main 6 over
2023-04-18 02:47:27 当前线程:main 7 over
2023-04-18 02:47:30 当前线程:main 8 over
2023-04-18 02:47:33 当前线程:main 9 over

可见在获取异步执行结果后,主线程会执行,异步执行完返回一个主线程执行一个,直到所有的都执行完;

1.6 Completable.join

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + Thread.currentThread().getName() + "开始执行异步任务11");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getTime() + Thread.currentThread().getName() + "执行异步任务完成11");
        }, executorService);
        CompletableFuture<Void> f2 = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + Thread.currentThread().getName() + "开始执行异步任务22");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getTime() + Thread.currentThread().getName() + "执行异步任务完成22");
        }, executorService);
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(f1, f2);
        voidCompletableFuture.join();
        System.out.println(getTime() + Thread.currentThread().getName() + "over");
        executorService.shutdownNow();
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }
}

输出
2023-04-18 03:12:44service-thread-0开始执行异步任务11
2023-04-18 03:12:44service-thread-1开始执行异步任务22
2023-04-18 03:12:45service-thread-0执行异步任务完成11
2023-04-18 03:12:49service-thread-1执行异步任务完成22
2023-04-18 03:12:49mainover

和get方法差不多,只是抛出异常方式有区别,建议用get;

1.7 Completable.anyof 有任一结果返回就返回

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //定义线程池
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<Void> f1 = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + Thread.currentThread().getName() + "开始执行异步任务11");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getTime() + Thread.currentThread().getName() + "执行异步任务完成11");
        }, executorService);
        CompletableFuture<Void> f2 = CompletableFuture.runAsync(() -> {
            System.out.println(getTime() + Thread.currentThread().getName() + "开始执行异步任务22");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getTime() + Thread.currentThread().getName() + "执行异步任务完成22");
        }, executorService);
        CompletableFuture<Object> objectCompletableFuture = CompletableFuture.anyOf(f1, f2);
        objectCompletableFuture.get();
        System.out.println(getTime() + Thread.currentThread().getName() + "over");
        executorService.shutdownNow();
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }
}

输出
2023-04-18 03:32:36service-thread-0开始执行异步任务11
2023-04-18 03:32:36service-thread-1开始执行异步任务22
2023-04-18 03:32:37service-thread-0执行异步任务完成11
2023-04-18 03:32:37mainover

1.8 CompletableFuture.completedFuture 返回一个计算好的CompletableFuture

@Slf4j
public class FutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        //定义线程池
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("service-thread-%d").build();
        ExecutorService executorService = new ThreadPoolExecutor(3, 5, 0L,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), factory,
                new ThreadPoolExecutor.AbortPolicy());
        CompletableFuture<List<String>> listCompletableFuture = CompletableFuture.completedFuture(getList());
        List<String> list = listCompletableFuture.get();
        System.out.println(getTime() + " " + Thread.currentThread().getName() + " " + JSON.toJSON(list));
        executorService.shutdownNow();
    }

    public static String getTime() {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return dateFormat.format(date);
    }

    public static List<String> getList() throws InterruptedException {
        List<String> list = Lists.newArrayList();
        for (int i = 0; i < 5; i++) {
            list.add(i + "");
            Thread.sleep(i * 1000);
            System.out.println(getTime() + " " + Thread.currentThread().getName() + " " + i);
        }
        return list;
    }
}

输出
2023-04-19 11:05:59 main 0
2023-04-19 11:06:00 main 1
2023-04-19 11:06:02 main 2
2023-04-19 11:06:05 main 3
2023-04-19 11:06:09 main 4
2023-04-19 11:06:09 main ["0","1","2","3","4"]

注意,这是在主线程中执行的;

2. @Async

2.1 简单举例

使用@Async注解开启异步任务,需要在主启动类上加@EnableAsync注解,先来一个简单的例子:
Controller层:

@RestController
@RequiredArgsConstructor
public class AsyncController {
    @Autowired
    private AsyncService asyncService;

    @PostMapping("/async")
    public String testAsync() {
        return asyncService.testAsync();
    }
}

Service层:

@Service
@Slf4j
@RequiredArgsConstructor
public class AsyncServiceImpl implements AsyncService {
    @Autowired
    private AsyncTask asyncTask;

    @Override
    public String testAsync() {
        log.info(Thread.currentThread().getName() + " start test async");
        Future<List<Integer>> listFuture = asyncTask.asyncJob();
        List<Integer> list;
        try {
            //在这里会阻塞主线程直到所有的异步线程执行完返回结果
            list = listFuture.get(10, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
        log.info(JSON.toJSONString(list));
        log.info(Thread.currentThread().getName() + " over test async");
        return "ok";
    }
}

自定义线程池,需要定义线程池名称"AsyncThreadPool":

@Configuration
@Slf4j
public class ThreadPoolConfig {

    @Bean(name = "AsyncThreadPool")
    public ExecutorService executorService() {
        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("async-%d").build();
        try {
            return new ThreadPoolExecutor(
                    10, 20, 0L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(10000), threadFactory, new ThreadPoolExecutor.AbortPolicy());
        } finally {
            log.info("async thread pool build");
        }
    }
}

异步任务逻辑层:

@Component
@Slf4j
public class AsyncTask {
    //使用系统默认线程池
//    @Async
    //使用自定义线程池
    @Async("AsyncThreadPool")
    public Future<List<Integer>> asyncJob() {
        List<Integer> list = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info(Thread.currentThread().getName() + " async job " + i);
            list.add(i);
        }
        return new AsyncResult<>(list);
    }
}

执行结果:
在这里插入图片描述
使用@Async注解开启异步任务,使用自定义线程池,标注线程池名字,如果不适用自定义线程池,将会使用相同默认线程池,默认线程池的最大线程数和任务队列都是Integer.MAX,并发数过大会导致OOM;
下面是使用系统默认线程池:
在这里插入图片描述

2.2 不适用Future.get方法阻塞

不使用Future.get方法去阻塞的话,主线程会先执行完,这种适用于需要快速返回,举个例子,用户购买某一个应用,购买成功之后,马上给用户提示购买成功,而购买服务所需要的一些配置可以在购买成功之后再去执行,先给用户展示购买成功,再去配置,哪怕后面服务的一些配置出问题,也要提示用户购买成功,之后对异步执行过程中的配置异常做补偿处理;
在这里插入图片描述

2.3 多个异步任务的处理

@Service
@Slf4j
@RequiredArgsConstructor
public class AsyncServiceImpl implements AsyncService {
    @Autowired
    private AsyncTask asyncTask;

    @Override
    public String testAsync() {
        log.info(Thread.currentThread().getName() + " start test async");
        Future<List<Integer>> listFuture = asyncTask.asyncJob();
        Future<List<Integer>> listFuture1 = asyncTask.asyncJobs();
        List<Integer> list;
        try {
            list = listFuture1.get(10, TimeUnit.SECONDS);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
        log.info(JSON.toJSONString(list));
        log.info(Thread.currentThread().getName() + " over test async");
        return "ok";
    }
}

从返回结果可以看出来,listFuture1.get会阻塞主线程,但是异步任务执行完成之后,不再阻塞主线程,主线程执行完毕,另一个异步任务继续执行;
在这里插入图片描述
要想异步任务在主线程之前执行完,可以通过调get方法:

        List<Future<?>> list1 = Lists.newArrayList();
        list1.add(listFuture);
        list1.add(listFuture1);
        list1.forEach(i->{
            try {
                i.get(10,TimeUnit.SECONDS);
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                throw new RuntimeException(e);
            }
        });

在这里插入图片描述

2.4 @Async失效的情况

@Service
@Slf4j
@RequiredArgsConstructor
public class AsyncServiceImpl implements AsyncService {

    @Override
    public String testAsync() {
        log.info(Thread.currentThread().getName() + " start test async");
        Future<List<Integer>> listFuture = asyncJob();
        log.info(Thread.currentThread().getName() + " over test async");
        return "ok";
    }

    @Async("AsyncThreadPool")
    public Future<List<Integer>> asyncJob() {
        List<Integer> list = Lists.newArrayList();
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info(Thread.currentThread().getName() + " async job " + i);
            list.add(i);
        }
        return new AsyncResult<>(list);
    }
}

可见都是在主线程执行的
在这里插入图片描述
Spring 在扫描bean的时候会扫描方法上是否包含@Async注解,动态地生成一个子类(即proxy代理类),当这个有注解的方法被调用的时候,实际上是由代理类来调用的。如果这个有注解的方法是被同一个类中的其他方法调用的,那么该方法的调用并没有通过代理类,而是直接通过原来的那个 bean,所以就失效了。所以调用方与被调方不能在同一个类,主要是使用了动态代理,同一个类的时候直接调用,不是通过生成的动态代理类调用。一般将要异步执行的方法单独抽取成一个类。

还有就是注解@Async的方法不是public方法、注解@Async的返回值只能为void或者Future、注解@Async方法使用static修饰也会失效;

类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象、在Async 方法上标注@Transactional是没用的,但在Async 方法调用的方法上标注@Transactional 是有效的;

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

Java中使用到的异步任务总结(CompletableFuture类,@Async注解) 的相关文章

  • 初始向量(IV)的CTR模式使用

    据我所知 CTR 模式不使用初始向量 它只需要一个计数器 用给定的密钥对其进行加密 然后将结果与明文进行异或以获得密文 其他分组密码模式 例如 CBC 在进行加密之前 会使用初始向量对明文进行异或 所以这是我的问题 我在 Java 中有以下
  • Java泛型 - 实现像map这样的高阶函数

    我决定用 Java 编写一些常见的高阶函数 map filter reduce 等 这些函数通过泛型实现类型安全 但我在一个特定函数中遇到通配符匹配问题 为了完整起见 函子接口是这样的 The interface containing th
  • 如何在谷歌地图中使用latlng字符串数组绘制多边形

    在我的应用程序中 我有包含 imagview 的 recyclerview 并且该 imageview 通过使用我存储在 sqlite 中的坐标包含静态地图图像 当我单击该图像时 我将该字符串数组格式的坐标传递给其他地图活动 然后使用该字符
  • JFreeChart - 创建移动图表时出现问题

    我在我的 java 应用程序中使用 JFreeChart Problem 我想绘制一个XY面积图 whose 域轴 x 轴 当我们开始绘制数据时应该自动水平滚动 我在中看到了同样的事情时间序列图表但我不想要任何时间系列图表 我只想要滚动的
  • Java 中支持多少维数组,例如 a[1][1][1][1]....[1]? [复制]

    这个问题在这里已经有答案了 Java支持多少维数组a 1 1 1 1 1 我可以为数组声明无限数量的维度吗 数组维数限制为 255 有趣的是 JLS定义的Java编程语言没有这样的限制 但是你可以在JVM规范 http docs oracl
  • 如何使 ScheduledExecutorService 在计划任务取消时自动终止

    我正在使用一个ScheduledExecutorService如果网络连接已打开超过几个小时 则关闭该连接 然而 在大多数情况下 网络连接在超时之前就关闭了 所以我取消了ScheduledFuture 在这种情况下 我还希望执行程序服务终止
  • 整数与 int 比较

    我是新来的java 我现在正在学习非原始整数类型java 我知道以下比较无效并引发编译错误 String str c Char chr c if str chr return true 上面的代码片段给了我 Test java lineNu
  • java:如何设置全局线程ID?

    是否有可能为线程设置唯一ID 在分布式系统中 线程是在许多不同的机器上创建的 例如通过 RMI 我需要它来创建日志消息 根据我的研究 我知道可以使用 log4j mdc ndc 来完成 但只能在单线程中完成 我的问题是 在创建线程时必须设置
  • 读取不失真的灰度 PNG 图像文件

    我需要读取和处理大量的灰度 PNG 文件 我的意思是 如果它们在 Photoshop 或 GIMP 中打开 则图像模式为灰度 而不是具有灰度值的 RGB 图像 ImageIO 似乎没有实现这一点 它似乎将所有图像文件视为 sRGB 这会破坏
  • Elasticsearch NodeBuilder 与 TransportClient

    对于其他 Elasticsearch 开发人员来说 这可能是一个非常简单 而且愚蠢 的问题 这两者之间有什么区别 我正在从 Java Web 应用程序连接到远程 Elasticsearch 服务器 到目前为止我一直在使用 Transport
  • java.lang.ClassCastException: [B 无法转换为 java.lang.String

    我编写了一个带有字段 LoginId 和密码的实体类 我使用 AES ENCRYPT 加密密码并将其存储在数据库中 我只想检索已解密的密码 所以 我使用 AES DECRYPT 使用本机查询是在 OPen JPA 2 0 中 我写的查询是
  • Visual Studio Code - Java 类路径不完整。只会报告语法错误

    在使用 python 获得了丰富的经验之后 我正在使用 java 迈出第一步 我正在运行的脚本是一个简单的 Java Swing Gui 它可以从命令行和 VS Code 中正常编译和运行 为了设置 java 调试环境 我使用 github
  • Wildfly 10.1 消耗所有核心

    我们最近将银行应用程序从 java 1 6 升级到 1 8 将 jboss 4 x 升级到 wildfly 10 1 我们观察到 java 消耗了机器上可用的所有核心 10 有人可以告诉是什么原因吗 通常情况下 jboss 4 x 的最大
  • 当通过 Map.put(K, V) 添加值时,是否必须通过 Map.get(K) 返回相同的实例?

    假设您有以下代码 Map
  • 通过 ssh 发送命令并读取输出结果

    我有代码通过 ssh 连接到远程服务器并向其发送 2 个或更多命令 例如 cd export home ops bin和 viewlinkload time 20131205 19 但我没有看到命令执行 也没有收到结果 我需要获取服务器返回
  • 使用 InputStream 通过 TCP 套接字接收多个图像

    每次我从相机捕获图像时 我试图将多个图像自动从我的 Android 手机一张一张地发送到服务器 PC 问题是read 函数仅在第一次时阻塞 因此 从技术上讲 只有一张图像被接收并完美显示 但在那之后当is read 回报 1 该功能不阻塞
  • 如何从Java中的连接获取查询字符串?

    我正在编写一个方法 尝试记录数据库调用 形成连接到它的连接 在查询之后 有很多地方调用方法 connect 来启动并调用 cleanUp 方法来结束 我不能并且不想修改每个地方 所以顺序是这样的 Connection con connect
  • 文档过滤器在 Java 中不起作用?

    在超过 10 个字符的文本字段中 它必须显示错误 为此 我使用了文档过滤器 JTextField field JTextField txtFld AbstractDocument document AbstractDocument fiel
  • 混合语言源目录布局

    我们正在运行一个使用多种不同语言的大型项目 Java Python PHP SQL 和 Perl 到目前为止 人们一直在自己的私有存储库中工作 但现在我们希望将整个项目合并到一个存储库中 现在的问题是 目录结构应该是什么样的 我们应该为每种
  • 安装 JDK 时出错:keytool 命令需要已安装的 proc fs (/proc)。 Linux 的 Windows 子系统

    我尝试在 Linux 的 Windows 子系统 Ubuntu 14 04 上安装 Oracle JDK 1 7 但出现以下错误 the keytool command requires a mounted proc fs proc Jav

随机推荐

  • 数字化转型建设的基本模型与能力构建

    数字经济的政策推动下 行业数字化转型建设如火如荼 本文提出了一种业务为主线的数字化转型建设的基本模型 数据应用业务链 并以数据应用业务链的业务的数据 数据的业务 业务的业务这三个环节探讨了数字化转型建设的能力构建及其基本过程并划分了可合作的
  • 关于激光雷达盲区0.4m问题

    https xw qq com amphtml 20220302A03F6I00 盲区 吸点 激光雷达探测器一般有几到几十纳秒的Dead Time Dead Time指是接收到一个激光脉冲后到再能接受一个新激光脉冲所需的最短时间 当一束激光
  • uniapp 微信小程序订阅(一次性订阅消息)

    首先我们需要了解微信小程序的一些基本的 才能知道我们要做什么 微信小程序消息订阅只有两种形式可以召唤出来 1 用户手动点击按钮 2 支付回调唤起 一次调用最多可订阅3条消息 小程序弹出后 可点击的情况 1 单纯点击取消 确认键 2 勾选了总
  • ajax降低性能,AJAX的性能改进

    AJAX的性能改进 简介 在Web窗体中 我们使用AJAX来从客户端 从JavaScript 调用服务器端方法 AJAX的内部使用XMLHttpRequest 我已经测试了不同的方式实现Ajax功能 另外 我有监测AJAX调用的性能和生命周
  • Introduction to NMOS and PMOS Transistors

    原文链接 https anysilicon com introduction to nmos and pmos transistors Introduction to NMOS and PMOS Transistors In this ar
  • 【网课平台】Day10.对接第三方:实现微信扫码登录

    文章目录 一 需求 微信扫码登录 1 接口文档 2 开发环境准备 3 接入分析 4 接口定义 5 申请令牌 6 查询用户信息 7 保存用户信息 一 需求 微信扫码登录 和第三方对接的流程 1 接口文档 找到第三方的接口文档 微信扫码登录 可
  • 基于python的爬虫实现

    定义 爬虫 Web crawler 也被称为网络爬虫 网络蜘蛛或网络机器人 是一种自动化程序 用于浏览互联网并收集网页内容 基本原理 爬虫的工作原理是通过发送HTTP请求从网页服务器获取网页的内容 然后解析网页并提取所需的数据 具体步骤如下
  • 让vscode正确识别webpack alias路径的方法

    一般的相对路径引入依赖文件 vscode能够正确识别 做出智能提示 但是有时候项目目录层级太深 写相对路径很长 非常容易出错 所以一般我们会在webpack中配置alias 使用短名来减少路径层级 如 import getUsers fro
  • 国内网络摄像机的端口及RTSP地址

    海康威视 默认IP地址 192 168 1 64 DHCP 用户名admin 密码自己设 端口 HTTP 端口 默认为 80 RTSP 端口 默认为 554 HTTPS 端 口 默认 443 和 服务端口 默认 8000 ONVIF端口 8
  • 揭秘阿里新一代SpringCloud学习指南:掌握最具中国特色的微服务组件

    SpringCloud Alibaba 的优势 阿里使用过的组件经历了考验 性能强悍 设计合理 现在开源出来给大家用 成套产品搭配完善的可视化界面给开发运维带来了极大的便利 搭建简单 学习曲线低 作为国内微服务领域的领军企业 阿里巴巴在微服
  • 自定义设置一个屏保程序

    用C语言写一个简单的窗口程序 目的是生成一个可视化的图形窗口 需要用到EasyX库 可在文章末尾的网盘链接中下载 该程序退出需左击鼠标 否则无法退出 include
  • Learning_the_shell

    昨天逛了www linuxcommand org 学习了shell的基本知识 对alias function type等基本命令有了比较深入的了解 还有就是对top kill ps jobs等进程命令有了更清晰的了解 特别是kill的参数问
  • MRI T1加权结构

    MRI是多参数成像 出于分析图像的方便 希望一帧MRI图像的灰度主要由一个特定的成像参数决定 这就是所谓的加权图像 weighted imaging WI 例如图像灰度主要由T1决定时就是T1加权图像 主要由T2决定时就是T2加权图像 主要
  • ubuntu18.04安装caffe(cpu版)

    主要根据ubuntu安装caffe这个博客 网上有些教程说要安装protobuf2 6 1 实际上只要有protobuf就行 版本无所谓 如果编译过程中出现google protobuf未定义的引用之类的报错 可能是protobuf版本和g
  • Python 类中pass语句

    Python pass 是空语句 是为了保持程序结构的完整性 pass 不做任何事情 一般用做占位语句 本文主要介绍Python 类中pass语句 原文地址 Python 类中pass语句
  • 普氏分析 matlab,降维和特征提取 - MATLAB & Simulink - MathWorks 中国

    特征选择 Learn about feature selection algorithms and explore the functions available for feature selection This topic intro
  • 10 分钟上手 Vue 组件 Vue-Draggable

    Vue 综合了 Angualr 和 React 的优点 因其易上手 轻量级 受到了广泛应用 成为了是时下火热的前端框架 吸引着越来越多的前端开发者 本文将通过一个最简单的拖拽例子带领大家快速上手 Vue 组件 Vue Draggable 首
  • 使用()控件的saveas方法可以将上传文件保存到服务器.,3.25.1 使用FileUpload控件上传文件...

    VB Protected Sub Button1 Click ByVal sender As Object ByVal e As System EventArgs If FileUpload1 HasFile Then Try FileUp
  • Android禁用第三方应用

    需要权限android Manifest permission CHANGE COMPONENT ENABLED STATE 而这个权限是只有system app才能使用 所以app需要系统签名 非system app即便在Android
  • Java中使用到的异步任务总结(CompletableFuture类,@Async注解)

    文章目录 1 CompletableFuture 1 1 Completable supplyAsync 1 2 Completable runAsync 1 3 get方法 1 4 使用自定义线程池 1 5 Completable all