JUC notes
- JUC concurrent programming (I) - multithreading review, Synchronized and Lock locks, Condition thread communication, eight Lock problem
- JUC concurrent programming (II) - set insecurity and solutions under concurrency, read-write lock, blocking queue
10. Callable review
Details: Multithreaded pickup
The difference between Callable and Runnable
- 1. Can have return value
- 2. Exceptions can be thrown
- 3. Different methods, run()/ call()
public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { // new Thread(new Runnable()).start(); // new Thread(new FutureTask<V>()). start(); Putting futuretask into thread is equivalent to putting Runnable into thread // new Thread(new FutureTask<V>( Callable )). start(); Callable into futuretask MyThread myThread = new MyThread(); FutureTask<String> task = new FutureTask<>(myThread); new Thread(task,"A").start(); new Thread(task,"B").start(); String s = task.get(); System.out.println(s); } static class MyThread implements Callable<String> { @Override public String call() { System.out.println("call()"); // Several call s will be printed return Thread.currentThread().getName()+"->call"; } } }
11. Thread pool
Pooling Technology: prepare some resources in advance, take them when necessary, and return them to me when they are used up.
Thread pool benefits:
- Reduce resource consumption
- Improve response speed
- Convenient management
Thread reuse, control the maximum concurrent number, manage threads
Key points: three methods, seven parameters and four rejection strategies
11.1 three methods
The three methods refer to the three methods for creating thread pools in the Executors tool class
- Executors. Newsinglethreadexecution(): create a single thread pool
- Executors. Newfixedthreadpool (int Num): create a thread pool with a fixed size of num
- Executors.newCachedThreadPool(): create a scalable thread pool, which is strong in case of strength and weak in case of weakness
public class ThreadPoolDemo { public static void main(String[] args) { ExecutorService threadPool = Executors.newSingleThreadExecutor();//Single thread pool // ExecutorService threadPool = Executors.newFixedThreadPool(5);// A thread pool with a fixed size of 5 // ExecutorService threadPool = Executors.newCachedThreadPool();// Create a scalable thread pool try { for (int i = 0; i < 100; i++) { //Use execute to create a thread threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+"created"); }); } } catch (Exception e) { e.printStackTrace(); } finally { //Remember to turn it off when you run out threadPool.shutdown(); } } }
11.2 seven parameters
First analyze a wave of source code
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService( new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
You can see that the essence of these three methods is the ThreadPoolExecutor() called. The seven parameters of this method are very important
public ThreadPoolExecutor(int corePoolSize, // Core thread pool size int maximumPoolSize, // Maximum core thread pool size long keepAliveTime, // After a timeout, it will be released if no one calls it TimeUnit unit, // Timeout unit: SECOND, MINUTE BlockingQueue<Runnable> workQueue, //Blocking queue ThreadFactory threadFactory, // Thread factory: it is used to create threads. Generally, it does not need to be moved RejectedExecutionHandler handler) { //Reject policy: 4 reject policies if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.acc = System.getSecurityManager() == null ? null : AccessController.getContext(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
As shown in the figure: image description of the above parameters
Attention! Attention!!!
Alibaba's development manual specifies that thread pools cannot be created using the three methods of Executors, but should be created using the original method of ThreadPoolExecutor
Big disadvantage: as shown in the figure, it will cause OOM
11.3 four rejection strategies
- new ThreadPoolExecutor.AbortPolicy() / / when the bank is full, someone else comes in. If this person is not handled, an exception is thrown
- new ThreadPoolExecutor.CallerRunsPolicy() / / where you come from, where you go!
- new ThreadPoolExecutor.DiscardPolicy() / / if the queue is full, the task will be lost and no exception will be thrown!
- new ThreadPoolExecutor.DiscardOldestPolicy() / / when the queue is full, try to compete with the earliest one without throwing an exception!
Now customize a thread pool:
public class ThreadPoolDemo02 { public static void main(String[] args) { ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());//The queue is full. Try to and The earliest competition will not throw exceptions! try { for (int i = 0; i < 9; i++) { threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" used"); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } } }
11.4 how to determine the size of the pool
Judge IO intensive and CPU intensive (pool tuning)
- 1. CPU intensive, several cores, that is, several cores, can maintain the highest CPU efficiency.
- Setting formula: number of threads = number of CPU cores + 1 (hyper thread)
- 2. IO intensive, judge the threads in your program that consume IO very much
- Setting formula: number of threads = (1 + thread waiting time / thread CPU time) * number of CPU cores * CPU utilization
- Or simple and crude: number of threads = 2 * number of CPU cores
Runtime.getRuntime().availableProcessors() gets the number of cores
public class ThreadPoolDemo02 { public static void main(String[] args) { System.out.println(Runtime.getRuntime().availableProcessors()); ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, Runtime.getRuntime().availableProcessors(),//Here, the maximum is set to the number of cores of the cpu 3, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy()); try { for (int i = 0; i < 9; i++) { threadPool.execute(()->{ System.out.println(Thread.currentThread().getName()+" used"); }); } } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } } }
12. Parallel computing ForkJoin
12.1 what is ForkJoin
ForkJoin appears in JDK 1.7 to execute tasks in parallel! So as to improve efficiency and deal with large amount of data
12.2 ForkJoin features
Job theft:
As shown in the figure above, ForkJoin maintains a double ended queue. After one queue is executed, you can steal tasks from other queues to assist in execution
12.3 ForkJoinTask and ForkJoinPool
ForkJoinTask
In fact, ForkJoinTask is a lightweight FutureTask
ForkJoinPool
ForkJoinPool is used to execute ForkJoinTask
Practice:
To use ForkJoin, we inherit an implementation class of ForkJoinTask and need to override the compute method
public class ForkJoinDemo extends RecursiveTask<Long> { @Override protected Long compute() { return null; } }
/** * The task of summation calculation! * 3000 6000(ForkJoin) 9000(Stream Parallel stream) * // How to use forkjoin * // 1,forkjoinPool Execute through it * // 2,Calculate the task forkjoinpool execute(ForkJoinTask task) * // 3. The calculation class should inherit ForkJoinTask */ public class ForkJoinDemo extends RecursiveTask<Long> { private Long start; // 1 private Long end; // 1990900000 // critical value private Long temp = 10000L; public ForkJoinDemo(Long start, Long end) { this.start = start; this.end = end; } @Override protected Long compute() { if ((end - start) < temp) { Long sum = 0L; for (Long i = start; i <= end; i++) { sum += i; } return sum; } else { // forkjoin recursion long middle = (start + end) / 2; // Intermediate value ForkJoinDemo task1 = new ForkJoinDemo(start, middle); task1.fork(); // Split the task and push the task into the thread queue ForkJoinDemo task2 = new ForkJoinDemo(middle + 1, end); task2.fork(); // Split the task and push the task into the thread queue return task1.join() + task2.join(); } } }
public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { test1(); //5509 is required for calculation test2(); //Calculation requires 3766 test3(); //The calculation requires 203 flow calculations yyds } // Ordinary programmer public static void test1(){ Long sum = 0L; long start = System.currentTimeMillis(); for (Long i = 1L; i <= 10_0000_0000; i++) { sum += i; } long end = System.currentTimeMillis(); System.out.println("sum="+sum+" Time:"+(end-start)); } // Will use ForkJoin public static void test2() throws ExecutionException, InterruptedException { long start = System.currentTimeMillis(); ForkJoinPool forkJoinPool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinDemo(0L, 10_0000_0000L); ForkJoinTask<Long> submit = forkJoinPool.submit(task);// Submit task Long sum = submit.get(); long end = System.currentTimeMillis(); System.out.println("sum="+sum+" Time:"+(end-start)); } public static void test3(){ long start = System.currentTimeMillis(); // Stream parallel stream () long sum = LongStream.rangeClosed(0L, 10_0000_0000L).parallel().reduce(0, Long::sum); long end = System.currentTimeMillis(); System.out.println("sum="+"Time:"+(end-start)); } }
13. Asynchronous callbacks to Future and FutureTask
13.1 Future
Take a look at the jdk documentation
As an interface, Future cancels the execution results of specific Runnable or Callable tasks, queries whether they are completed, and obtains the results.
If necessary, you can get the execution result through the get method, which will block until the task returns the result.
The implementation classes include ForkJoinTask (mentioned above) and FutureTask (let's talk about FutureTask next)
13.2 FutureTask
To view the jdk documentation:
This class provides a basic implementation of Future, with methods to start and cancel calculation, query whether the calculation is complete, and retrieve the calculation results. The results can only be retrieved after the calculation is completed; If the calculation has not been completed, the get method will block it. Once the calculation is complete, you cannot restart or cancel the calculation (unless the calculation is called using runAndReset()).
FutureTask has three statuses:
-
Not started. FutureTask. Futuretask is not started before the run () method is executed. When creating a futuretask, futuretask has not been executed Futuretask was not started before the run () method.
-
Started. FutureTask. Futuretask is started while the run () method is being executed.
-
Completed. FutureTask. The execution of the run () method ends, or futuretask. Exe is called The cancel (...) method cancels the task or throws an exception during the execution of the task, which are called the completed state of futuretask.
Demo:
public class CallableDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { MyThread myThread = new MyThread(); FutureTask<String> task = new FutureTask<>(myThread); new Thread(task,"A").start(); new Thread(task,"B").start(); String s = task.get(); System.out.println(s); } static class MyThread implements Callable<String> { @Override public String call() { System.out.println("call()"); // One call will be printed. The status of futureTask will be changed once it is executed. It cannot be executed again return Thread.currentThread().getName()+"->call"; } } }
13.3 CompletableFuture
When FutureTask obtains the execution results of asynchronous tasks, either call get to block or poll isDone to actively query whether it is completed. Both methods are not very good and will force the main thread to wait.
After completing a task phase, completable future can actively notify the next phase
Simple use:
- runAsync: callback without return value
- supplyAsync: callback with return value
public class CompletableFutureDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { test1(); test2(); } public static void test1() throws ExecutionException, InterruptedException { //runAsync asynchronous callback with no return value CompletableFuture<Void> completableFuture =CompletableFuture.runAsync(()->{ try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runAsync=>Void"); }); System.out.println("1111"); completableFuture.get(); // Get blocking execution results } public static void test2() throws ExecutionException, InterruptedException { // supplyAsync asynchronous callback with return value // ajax, successful and failed callbacks // The error message is returned; CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{ System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer"); int i = 10/0; return 1024; }); System.out.println(completableFuture.whenComplete((t, u) -> { System.out.println("t=>" + t); // Normal return result System.out.println("u=>" + u); // Error message: Java util. concurrent. CompletionException: java. lang.ArithmeticException: / byzero }).exceptionally((e) -> { System.out.println(e.getMessage()); return 233; // You can get the return result of the error }).get()); } }