[elegant code] line 04-1 completes multithreading. Stop writing runnable
Welcome to b station official account / public number [hexagon warrior Xia Ning], a man who wants to fill all the indicators. The article has been published in github directory Included.
The handsome and beautiful in front of the screen, if it helps you, please like it and add a collection, which is really important to me. Don't worry about where you go next time.
1. Background introduction
The completable future and anonymous functions provided by Java 8 allow us to multithread one line of code
2. Establish related categories
2.1.ThreadEntity
Entity classes for multithreaded testing
public class ThreadEntity { private int num; private int price; public int countPrice(){ price = RandomUtils.nextInt(); try { System.out.println(num); // Wait randomly for 1 ~ 10 seconds Thread.sleep(RandomUtils.nextInt(1, 10) * 1000); System.out.println(num); } catch (InterruptedException e) { e.printStackTrace(); } return price; } }
2.2.ThreadPoolManager
/** * tasks The number of tasks per second, 200 by default, is calculated based on the number of accesses and where the thread pool is used * taskCost: The time spent on each task is 0.1s by default * responseTime: The maximum response time is 1s by default, and the maximum endurance time of general users is 3 seconds * * @author seal email:876651109@qq.com * @date 2020/5/30 10:08 AM */ @Data @Slf4j @Configuration public class ThreadPoolManager { /** * The average response time defaults to 2 seconds */ private static final float ALL_COST_AVG = 2F; /** * The average IO time defaults to 1.5 seconds */ private static final float IO_COST_AVG = 1.5F; /** * Server cores */ private static final int SIZE_PROCESSOR = Runtime.getRuntime().availableProcessors(); /** * https://www.cnblogs.com/dennyzhangdd/p/6909771.html?utm_source=itdadao&utm_medium=referral * Blocking coefficient = blocking time / (blocking time + calculation time) * Number of threads = number of cores / (1-blocking coefficient) * Equivalent to the number of cpu cores * cpu utilization * (1 + ratio of waiting time to calculation time) * N+1 Usually optimal efficiency * <p> * https://blog.51cto.com/13527416/2056080 */ private static final int SIZE_CORE_POOL = SIZE_PROCESSOR + 1; /** * The maximum number of thread pool maintenance will be consistent with the number of core threads by default, which is meaningless. In a conservative case, 2cpu is taken * Or simply calculate the number of CPUs with thread pool size = ((thread IO time + thread CPU time) / thread CPU time)** * Time consumed by request / (time consumed by request - DB processing) * number of CPUs, focusing on cpu waiting time, usually database db time * According to the usual 2-second display interface, the database operation takes 1.5 seconds (2/0.5)*n, which is actually optimizing the waiting time * <p> * The default 4n is 8-core 32 threads */ private static final int SIZE_MAX_POOL = (int) (SIZE_PROCESSOR * (ALL_COST_AVG / (ALL_COST_AVG - IO_COST_AVG))); /** * The queue length of the thread pool is integer maximum by default. Dubbo uses 1000. Unlimited will cause the user's tasks to queue all the time. You should select the appropriateness to discard, * Tolerable time 6, others are abandoned * SIZE_MAX_POOL/IO_COST_AVG=The number of tasks that can be processed per second. The default is * Tolerable time 6 * number of tasks per second = X number of queues */ private static final int SIZE_QUEUE = (int) (6 * (SIZE_MAX_POOL / IO_COST_AVG)); /** * Thread pool concrete class * LinkedBlockingDeque It is commonly used for fixed threads, and SynchronousQueue is commonly used for cache thread pool * Executors.newCachedThreadPool()Often used for short-term tasks * <p> * Thread factory selection, little difference * spring customizablethreadfactory and new customizablethreadfactory ("springthread pool -") * guava Threadfactorybuilder, new threadfactorybuilder() setNameFormat("retryClient-pool-"). build(); * apache-lang Basicthreadfactory, new basicthreadfactory Builder(). namingPattern("basicThreadFactory-"). build() * <p> * Default AbortPolicy for policies with full queues */ private static ThreadPoolManager threadPoolManager = new ThreadPoolManager(); private final ThreadPoolExecutor pool = new ThreadPoolExecutor( SIZE_CORE_POOL, SIZE_MAX_POOL, 30L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(SIZE_QUEUE), new CustomizableThreadFactory("springThread-pool-"), new ThreadPoolExecutor.AbortPolicy() ); private void prepare() { if (pool.isShutdown() && !pool.prestartCoreThread()) { int coreSize = pool.prestartAllCoreThreads(); System.out.println("Current thread pool"); } } public static ThreadPoolManager getInstance() { if (threadPoolManager != null) { ThreadPoolExecutor pool = threadPoolManager.pool; } return threadPoolManager; } }
3. Core code
3.1. Parallel stream
Parallel is a parallel core. It can be found that there are multiple threads running inside, but the order will be arranged after collect ion, so don't worry. Small projects can be used. For large projects, it is recommended to be honest and use your own thread pool. The fork/join provided by JDK does not fit the business
System.out.println(Stream.of(1, 2, 3, 4, 5, 6).parallel().map(l -> { System.out.println(l); return l; }).collect(Collectors.toList()));
The output is as follows. The output is random because of multithreading, but the final result does not change because collect ion is used
2 6 4 5 3 1 [1, 2, 3, 4, 5, 6]
3.2. Synchronization code
This can eliminate the need to implement the thread interface, but we still need to consider the discarding when the queue is full
List<ThreadEntity> listEntity = IntStream.range(0, 10).mapToObj(x -> ThreadEntity.builder().num(x).build()).collect(Collectors.toList()); List<CompletableFuture<Integer>> listCompletableFuture = listEntity.stream().map(x -> { try { // Here threadpoolmanager getInstance(). If getpool () does not pass this parameter, the default commonPool will be used. trycatch is generally not written if there are no special requirements return CompletableFuture.supplyAsync(() -> x.countPrice(), ThreadPoolManager.getInstance().getPool()); } catch (RejectedExecutionException e) { System.out.println("reject" + x); log.error("", e); return null; } }).collect(Collectors.toList()); List<Integer> result = listCompletableFuture.stream().map(CompletableFuture::join).collect(Collectors.toList()); System.out.println(result); System.out.println(listEntity);
The output is as follows. You can see that the operation is carried out in a multi-threaded manner, but the results are consistent with the original
start6 start9 start0 start3 start2 start1 start8 start5 start4 start7 end3 end8 end5 end7 end9 end1 end2 end6 end0 end4 [131523688, 1491605535, 222657954, 132274662, 1134597171, 2057763841, 1168687436, 1842194861, 1264173480, 56446450] [ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@7d6f201, num=0, price=131523688), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@58e825f3, num=1, price=1491605535), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@d458bb1, num=2, price=222657954), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@7e26830, num=3, price=132274662), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@43a0a2b8, num=4, price=1134597171), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@7aa70ac1, num=5, price=2057763841), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@45a8d047, num=6, price=1168687436), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@6dcdb8e3, num=7, price=1842194861), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@4b59d119, num=8, price=1264173480), ThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@35d5d9e, num=9, price=56446450)]
If intstream If range (0, 10) is changed to (0, 1000), the following error will be rejected
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$AsyncSupply@5af97850 rejected from java.util.concurrent.ThreadPoolExecutor@491666ad[Running, pool size = 64, active threads = 64, queued tasks = 256, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063) at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830) at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379) at java.util.concurrent.CompletableFuture.asyncSupplyStage(CompletableFuture.java:1618) at java.util.concurrent.CompletableFuture.supplyAsync(CompletableFuture.java:1843) at com.example.demo.lesson.grace.thread.TestMain.lambda$threadEx1$2(TestMain.java:34) at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) at com.example.demo.lesson.grace.thread.TestMain.threadEx1(TestMain.java:41) at com.example.demo.lesson.grace.thread.TestMain.main(TestMain.java:26) rejectThreadEntity(super=com.example.demo.lesson.grace.thread.ThreadEntity@1a9, num=366)
3.3. Asynchronous code
The following code can be abbreviated directly into one line, which makes it extremely convenient to deal with asynchronous tasks
CompletableFuture.runAsync(() -> fun())
List<ThreadEntity> listEntity = IntStream.range(0, 500).mapToObj(x -> ThreadEntity.builder().num(x).build()).collect(Collectors.toList()); List<CompletableFuture> listCompletableFuture = listEntity.stream().map(x -> { try { // Here threadpoolmanager getInstance(). If getpool () does not pass this parameter, the default commonPool will be used. trycatch is generally not written if there are no special requirements return CompletableFuture.runAsync(() -> x.countPrice(), ThreadPoolManager.getInstance().getPool()); } catch (RejectedExecutionException e) { System.out.println("reject" + x); return null; } }).collect(Collectors.toList()); listCompletableFuture.stream().map(CompletableFuture::join); System.out.println("1234"); // One line multithreading asynchronous execution writing method CompletableFuture.runAsync(() -> System.out.println(1));
The output is as follows. You can see that the main thread has ended and other sub threads are outputting. There are no waiting multithreads at all
1234 1 start7 start0 start6 start5 start4 start2 start8 start1 start9 start3 end8 end4 end9 end6 end2 end0 end1 end3 end5 end7