经常看到基本数据类型存放位置的内容,有些就说基本类型都在栈中,有些说基本类型在堆中,这其实要分变量的类型来说明.
java基本数据类型是指byte, short, int, long, float, double, char, boolean这八种类型。它们的存放位置取决于它们的声明位置和作用域。一般来说,有以下几种情况:
如果基本数据类型是局部变量,那么它们存放在栈(stack)中。栈是每个线程独享的内存区域,用于存储方法调用时的参数和临时变量。栈中的变量随着方法的执行而创建和销毁,不需要垃圾回收。
如果基本数据类型是实例变量(也叫成员变量),那么它们存放在堆(heap)中。堆是所有线程共享的内存区域,用于存储对象和数组。堆中的变量随着对象的创建和销毁而分配和回收内存,需要垃圾回收。
如果基本数据类型是类变量(也叫静态变量),那么它们存放在方法区(method area)中。方法区也是所有线程共享的内存区域,用于存储类的信息,包括静态变量和常量。方法区中的变量随着类的加载和卸载而分配和回收内存,也需要垃圾回收。
下面是一些例子:
JAVAint a = 10; //局部变量,存放在栈中
class Test { int b = 20; //实例变量,存放在堆中 static int c = 30; //类变量,存放在方法区中 }
Test t = new Test(); //对象引用,存放在栈中,指向堆中的对象
int[] arr = new int[10]; //数组引用,存放在栈中,指向堆中的数组
从JDK1.5开始,为了把工作单元与执行机制分离开,Executor框架诞生了,他是一个用于统一创建与运行的接口。Executor框架实现的就是线程池的功能。
Executor 是一个接口,定义了一个接收runnable对象的方法executor。
ThreadPoolExecutor继承abstrctExecutorService,用于创建线程池
ForkjoinPool 继承abstrctExecutorService,大任务分为小任务
需求前提
校验当前签收数量与本批送出数量是否一致,不一致给出缺少信息,关键词 两个list
public List<RecMrIndexBySendOutBatchNoListResponse> saveBatchPaperRecevieByCheck(RecMrIndexReceiveRequest request) { List<RecMrIndexEntity> recMrIndexEntityList=request.getRecMrIndexEntities().stream() .filter(i->i.getSendOutBatchNo()!=null).collect(Collectors.toList()); List<RecMrIndexBySendOutBatchNoListResponse> checkResponseList=new ArrayList<>(); //去除重复的送出号,去除为null的 List<String> batchNoList = recMrIndexEntityList.stream().map(RecMrIndexEntity::getSendOutBatchNo).distinct().collect(Collectors.toList()); if (CollectionUtils.isEmpty(batchNoList)){ return checkResponseList; } for (int i = 0; i < batchNoList.size(); i++) { String batchNo =batchNoList.get(i); if (StrUtil.isNotBlank(batchNo)){ List<RecMrIndexEntity> list=recMrIndexEntityList.stream() .filter((recMrIndex)->recMrIndex.getSendOutBatchNo().equals(batchNo)) .collect(Collectors.toList()); List<RecMrIndexBySendOutBatchNoListResponse> selectResponseList =baseMapper.getListBySendOutBatchNo(batchNo); if(list.size()==selectResponseList.size()){ continue; }else{ RecMrIndexBySendOutBatchNoListResponse selectResponse; Iterator<RecMrIndexBySendOutBatchNoListResponse> iterator= selectResponseList.iterator(); while (iterator.hasNext()){ selectResponse= iterator.next(); for (RecMrIndexEntity oldEntity:list){ if (selectResponse.getPatientId().equals(oldEntity.getPatientId()) && selectResponse.getVisitNo().equals(oldEntity.getVisitNo())){ iterator.remove(); } } } //合并过滤后的数据 checkResponseList.addAll(selectResponseList); } } } //再去除一次重复数据 return checkResponseList.stream().distinct().collect(Collectors.toList());
这个代码块的主要是对于Steam流的一些简单使用,通过Stream流可以快速得到送出号的列表,并且去除重复元素和空元素,再采用迭代器去除和另一个List中相同的元素,得到新的列表
以前需要异步执行一个任务时,一般是用Thread或者线程池Executor去创建。如果需要返回值,则是调用Executor.submit获取Future。但是多个线程存在依赖组合,我们又能怎么办?可使用同步组件CountDownLatch、CyclicBarrier等;其实有简单的方法,就是用CompeletableFuture
java//使用内置线程ForkJoinPool.commonPool(),根据supplier构建执行任务
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
//指定自定义线程,根据supplier构建执行任务
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
java//使用内置线程ForkJoinPool.commonPool(),根据runnable构建执行任务
public static CompletableFuture<Void> runAsync(Runnable runnable)
//指定自定义线程,根据runnable构建执行任务
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
javaExecutorService executor = Executors.newSingleThreadExecutor();
CompletableFuture<Void> rFuture = CompletableFuture
.runAsync(() -> System.out.println("hello siting"), executor);
//supplyAsync的使用
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> {
System.out.print("hello ");
return "siting";
}, executor);
//阻塞等待,runAsync 的future 无返回值,输出null
System.out.println(rFuture.join());
//阻塞等待
String name = future.join();
System.out.println(name);
executor.shutdown(); // 线程池需要关闭
--------输出结果--------
hello siting
null
hello siting
简单来说,并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。 Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。 Stream API 可以声明性地通过 parallel() 与sequential() 在并行流与顺序流之间进行切换 。
Fork/Join 框架: 就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总 。
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上。在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。而在fork/join框架的实现中,如果某个子任务由于等待另外一个子任务的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子任务来执行。这种方式减少了线程的等待时间,提高了程序的性能。