例如:
private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, Runtime.getRuntime().availableProcessors() * 2,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ptyadapter-qd-%d").build());
这段代码次要是定义了一个线程池 EXECUTOR_SERVICE 以及创立该线程池的一些参数和属性。
线程池是一种常见的治理线程的技术,它可能无效的控制线程的数量、复用线程、治理线程的生命周期和优化线程的性能等等。在该代码中,指定了线程池的总容量为 CPU 核数的两倍,应用的队列类型为 LinkedBlockingQueue,它是一个基于链表实现的无界阻塞队列,能够存储任意数量的元素。队列中的工作会期待线程池中闲暇的线程去执行,如果没有闲暇线程则会始终阻塞,期待有闲暇线程后再去执行。
该线程池中的线程都被标记为守护线程(daemon=true),即当主线程完结时,这些子线程也会随之完结。线程的名称采纳了相似于 ptyadapter-qd-1 这样的命名形式,数字局部是线程池内的线程计数器值。
具体参数的含意如下:
corePoolSize:线程池中保留的最小线程数。
maximumPoolSize:线程池中容许存在的最大线程数。
keepAliveTime:线程池中超过 corePoolSize 线程数目的闲暇线程在终止之前期待新工作的最长工夫。
unit:keepAliveTime 工夫单位。
workQueue:用于贮存期待执行工作的队列,其中可寄存有限个元素。
threadFactory:线程池中创立新线程的线程工厂。
这段代码的作用是在初始化时创立一个线程池,用于并发解决一些耗时的工作,并且该线程池具备较好的性能和容错机制。咱们能够通过调用 EXECUTOR_SERVICE.submit() 办法来提交一个工作到该线程池中,该线程池会依据理论状况来调度和执行这个工作。这种做法能够无效地进步程序的并发性能,并且不会像间接创立线程一样造成过多的线程资源节约。
while (true) {list.forEach((key, value) ->{Future<?> future = EXECUTOR_SERVICE.submit(() -> {if ("2".equals(value)) {return;}
if ("1".equals(value)) {return;}
// 结构 http 申请
BufferedReader reader = null;
VoucherRetionVo efmVouBillRelation = new VoucherRetionVo();
efmVouBillRelation.setIpConfig(key);
efmVouBillRelation.setMaxNum(size.get());
try {ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValueAsString(efmVouBillRelation);
String url = "http://" + key + "/pty/online/gz";
URL requestUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
connection.getOutputStream().write(objectMapper.writeValueAsString(efmVouBillRelation).getBytes());
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
} catch (Exception e) {LOG.error("拜访谬误请查看", e);
} finally {if (null != reader) {
try {reader.close();
} catch (IOException e) {e.printStackTrace();
}
}
}
if (size.get() == 0) {LOG.info("工作实现,上班");
return;
}
size.getAndDecrement();});
taskList.add(future);
});
for (Future<?> future : taskList) {future.get(120, TimeUnit.SECONDS);
}
// 达到要求完结循环
if (size.get() == 0) {LOG.info("工作实现,上班");
break;
}
}
这段代码蕴含一个有限循环,其中蕴含了线程池的调用,用于并发解决一些工作。
首先遍历 list 中的每个键值对,key 是字符串类型的 IP 地址,value 值类型为字符串,其值别离为 “1” 或 “2”。如果 value 值等于 “2”,示意该服务须要重启,间接跳过;如果 value 值等于 “1”,示意该服务正在生成原始单据,也间接跳过。其余状况下,将依据 key 和 size 参数结构一个 HTTP 申请,并将该申请提交到线程池中,以便异步地并发解决这些申请。
具体步骤如下:
创立一个 VoucherRetionVo 对象,并设置相干属性值。
依据 key 结构 HTTP 申请的 URL。
创立一个 URL 对象和一个 HttpURLConnection 对象,设置相干属性值和申请头信息。
向 HTTP 申请中写入申请体(即 VoucherRetionVo 对象序列化后的 JSON 字符串)。
发送 HTTP 申请,并读取响应后果。
敞开相干的 IO 流资源。
如果 size 值为 0,示意工作曾经全副实现,退出循环。
注意事项:
通过调用 Future.get() 办法阻塞线程,期待该线程执行结束并返回后果。
须要在 try-catch-finally 中开释 IO 资源。
整个循环在每次执行之前须要期待上一次执行完结,即先期待以后线程池中的所有工作执行完结,而后再持续下一次循环,直到工作全副实现。
Future.get() 办法用于阻塞以后线程并期待异步工作执行实现并返回后果。当线程池中的某个工作执行实现后,能够通过调用 Future.get() 办法获取该工作的执行后果。如果在指定工夫内(在这段代码中为 120 秒)工作未能执行结束,则会抛出 TimeoutException 异样。
如果你须要获取异步工作的执行后果,那么就须要应用 Future.get() 办法并在其中进行解决。在本段代码中,并没有对异步工作的返回值进行解决,而是只是期待工作执行结束,因而不须要应用该办法来获取异步工作的返回值。如果你须要获取异步工作的执行后果,请批改代码,在 submit 办法返回的 Future 对象上调用 get 办法以获取异步工作的返回值,并对其进行相应的解决。
Future 的作用:
应用 Future 对象能够实现异步计算(即线程池中的工作)的后果获取。通常状况下,咱们须要期待某个或某些异步工作执行结束能力进行下一步操作(例如获取异步工作的返回值并依据其后果进行相应的解决),这时候就能够应用 Future。
具体地说,将异步工作提交到线程池后,线程池会返回一个 Future 对象,这个对象能够用来查问工作以后的执行状态,或期待工作执行实现并返回执行后果。在期待工作执行实现时,能够应用 Future.get() 办法阻塞以后线程,直到异步工作执行实现并返回异步工作的执行后果。
此外,Future 还能够用于治理多个并发的异步工作。例如,能够通过 Future 对象来实现异步工作的超时机制、勾销异步工作的执行等。另外一些高级性能,例如,把多个 Future 组合成一个 Future,使它们执行结束后再执行某些操作,也能够应用 Future 来实现。
因而,应用 Future 能够简化异步工作的治理和管制,进步程序的并发性和效率。