当前位置:网站首页>28000 word summary of callable and future interview knowledge points. After reading it, I went directly to ByteDance. Forgive me for being a little floating (Part 2)
28000 word summary of callable and future interview knowledge points. After reading it, I went directly to ByteDance. Forgive me for being a little floating (Part 2)
2022-06-29 13:57:00 【Hua Weiyun】
Hello everyone , I'm glacier ~~
stay Java In multithreading programming , except Thread Classes and Runnable Outside the interface , It has to be said that Callable Interface Future The interface . Using inheritance Thread Class or implementation Runnable Thread of interface , Unable to return final execution result data , Can only wait for thread execution to complete . here , If you want to get the return result of thread execution , that ,Callable and Future That comes in handy .
notes : The whole process of the article is high energy , Recommended collection , If the article helps you a little , Guys, one button three times , Thank you very much! ~~
The depth resolution Future Interface
1.Future Interface
Future yes JDK1.5 New asynchronous programming interface , The source code is as follows .
package java.util.concurrent;public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}You can see , stay Future Interface , In all, it defines 5 Abstract methods . Next , Let's talk about this 5 The meaning of a method .
- cancel(boolean)
Cancel the execution of the task , Receive one boolean Parameters of type , Successfully cancelled the mission , Then return to true, Otherwise return to false. When the task is done , When it is over or cannot be cancelled for other reasons , Method will return false, Indicates that the task cancellation failed . This method is called when the task is not started , And the result returns true( Cancellation successful ), The current task is no longer running . If the task has been started , According to the current delivery boolean Type to determine whether to interrupt the currently running thread to cancel the currently running task .
- isCancelled()
Determine whether the task is cancelled before it is completed , If the task is cancelled before it is completed , Then return to true; otherwise , return false.
Here's a detail : Only the task is not started , Or it's canceled before it's done , Will return true, Indicates that the task has been successfully cancelled . Everything else will come back false.
- isDone()
Judge whether the task has been completed , If the mission ends normally 、 Throw an exception to exit 、 Be cancelled , Will return to true, Indicates that the task has been completed .
- get()
When the task is completed , Return the result data of the task directly ; When the task is not finished , Wait for the task to complete and return the result data of the task .
- get(long, TimeUnit)
When the task is completed , Return the result data of the task directly ; When the task is not finished , Waiting for the task to complete , And set the timeout waiting time . The task is completed within the timeout period , Returns the result ; otherwise , Throw out TimeoutException abnormal .
2.RunnableFuture Interface
Future Interface has an important sub interface , That's it RunnableFuture Interface ,RunnableFuture The interface not only inherits Future Interface , And inherited java.lang.Runnable Interface , The source code is as follows .
package java.util.concurrent;public interface RunnableFuture<V> extends Runnable, Future<V> { void run();}here , Ask me ,RunnableFuture There are several abstract methods in the interface ? Think about it and then ! Ha ha ha ...
This interface is relatively simple run() Methods are the methods that are called when the task is run .
3.FutureTask class
FutureTask Class is RunnableFuture Interface is a very important implementation class , It has achieved RunnableFuture Interface 、Future Interface and Runnable All methods of the interface .FutureTask Class source code is more , This is not pasted , Let's go to java.util.concurrent Check out .
(1)FutureTask Variables and constants in classes
stay FutureTask Class first defines a state variable state, This variable uses volatile Keyword modification , here , You just need to know volatile Keyword to achieve thread safety through memory barrier and disallowing reordering optimization , In depth analysis will be conducted separately in the future volatile Keyword is how to ensure thread safety . Then , The state constants of several tasks are defined , As shown below .
private volatile int state;private static final int NEW = 0;private static final int COMPLETING = 1;private static final int NORMAL = 2;private static final int EXCEPTIONAL = 3;private static final int CANCELLED = 4;private static final int INTERRUPTING = 5;private static final int INTERRUPTED = 6;among , Several possible state change processes are given in the code comments , As shown below .
NEW -> COMPLETING -> NORMALNEW -> COMPLETING -> EXCEPTIONALNEW -> CANCELLEDNEW -> INTERRUPTING -> INTERRUPTEDNext , Several other member variables are defined , As shown below .
private Callable<V> callable;private Object outcome; private volatile Thread runner;private volatile WaitNode waiters;And see what we're familiar with Callable The interface ,Callable Interface that must be used to call call() Methods to perform specific tasks .
outcome:Object type , Said by get() Method to get the result data or exception information .
runner: function Callable The thread of , It will be used during operation CAS Ensure thread safety , All you need to know here is CAS yes Java One way to keep threads safe , We will analyze it in depth in the following articles CAS How to ensure thread safety .
waiters:WaitNode Variable of type , Represents the stack of waiting threads , stay FutureTask In the implementation of , Will pass CAS Switch the running state of the task with this stack .
to glance at WaitNode The definition of a class , As shown below .
static final class WaitNode { volatile Thread thread; volatile WaitNode next; WaitNode() { thread = Thread.currentThread(); }}You can see ,WaitNode Class is FutureTask Static inner class of class , One is defined in the class Thread Member variables and point to the next WaitNode Reference to node . Among them, through the construction method thread Variable set to current thread .
(2) Construction method
Next , yes FutureTask Two construction methods of , Relatively simple , As shown below .
public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW;}public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); this.state = NEW;}(3) Whether to cancel and complete the method
Continue to look down at the source code , A way to see if a task is cancelled , And the way a task is done , As shown below .
public boolean isCancelled() { return state >= CANCELLED;}public boolean isDone() { return state != NEW;}Of the two methods , They all determine whether the task has been cancelled or completed by judging the status of the task . Why do you judge like this ? Look again FutureTask Class to discover , The definition of constant is regular , It's not a random definition . among , Greater than or equal to CANCELLED The constant of is CANCELLED、INTERRUPTING and INTERRUPTED, These three states can indicate that the thread has been canceled . When the state is not equal to NEW when , It means that the task has been completed .
Through here , You can learn a little : Later in the coding process , Define the state you use according to the rules , Especially when it comes to operations with frequent state changes in the business , Regular state can make business processing more efficient , This is what you can learn from other people's source code design , here , I suggest you read more about the excellent open source framework written by others .
(4) Cancellation method
Let's continue to look down at the source code , Next , To see is cancel(boolean) Method , As shown below .
public boolean cancel(boolean mayInterruptIfRunning) { if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false; try { // in case call to interrupt throws exception if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) t.interrupt(); } finally { // final state UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); } } } finally { finishCompletion(); } return true;}Next , Take apart cancel(boolean) Method . stay cancel(boolean) In the method , First, judge the state of the task and CAS The result of the operation , If the state of the task is not equal to NEW perhaps CAS The operation returns false, Then return directly false, Indicates that the task cancellation failed . As shown below .
if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED))) return false;Next , stay try Block of code , First, judge whether the thread of the current task can be interrupted to cancel the running of the task . If you can interrupt the thread of the current task , Take a Thread Temporary variable to point to the thread running the task , When the variable pointed to is not empty , Calling the interrupt() Method to interrupt the thread , Finally, mark the thread as interrupted . As shown below .
try { if (mayInterruptIfRunning) { try { Thread t = runner; if (t != null) t.interrupt(); } finally { // final state UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED); } }}here , It is found that changing task state uses UNSAFE.putOrderedInt() Method , What the hell is this method ? Click in and have a look , As shown below .
public native void putOrderedInt(Object var1, long var2, int var4);You can see , Another local approach , Hey , I don't care about it here , Follow up articles will explain the role of these methods .
Next ,cancel(boolean) Methods go into finally Code block , As shown below .
finally { finishCompletion();}You can see in the finallly The code block is called. finishCompletion() Method , seeing the name of a thing one thinks of its function ,finishCompletion() Method to end a task , Let's see how it works . Point to finishCompletion() Take a look at , As shown below .
private void finishCompletion() { // assert state > COMPLETING; for (WaitNode q; (q = waiters) != null;) { if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; LockSupport.unpark(t); } WaitNode next = q.next; if (next == null) break; q.next = null; // unlink to help gc q = next; } break; } } done(); callable = null; // to reduce footprint}stay finishCompletion() In the method , So let's define a for loop , The cycle termination factor is waiters by null, In circulation , Judge CAS Successful operation , If successful if Logic in conditions . First , Define a for Spin cycle , In a spin loop , Wake up the WaitNode Threads in the stack , Make it run . When WaitNode After the thread in the stack runs , adopt break Exit the outer layer for loop . Next call done() Method .done() What the hell is the method ? Click in and have a look , As shown below .
protected void done() { }You can see ,done() A method is an empty method body , Let subclasses implement specific business logic .
When it comes to our specific business , Need to cancel the mission , Perform some additional business logic , You can override... In subclasses done() Method implementation .
(5)get() Method
Keep looking down FutureTask Class code ,FutureTask Class implements two get() Method , As shown below .
public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L); return report(s);}public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { if (unit == null) throw new NullPointerException(); int s = state; if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING) throw new TimeoutException(); return report(s);}No parameters get() The method is when the task is not finished , It will block , Until the task result is returned . Parametric get() The method is when the task is not completed , And the waiting time exceeds the timeout , Meeting TimeoutException abnormal .
Two get() The main logic of the method is similar , One has no timeout settings , One has a timeout setting , Here's the main logic . Determine whether the current state of the task is less than or equal to COMPLETING, in other words , The task is NEW The state or COMPLETING, call awaitDone() Method , look down awaitDone() Method implementation , As shown below .
private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; } else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } else LockSupport.park(this); }}Next , Take apart awaitDone() Method . stay awaitDone() In the method , The most important thing is for Spin cycle , In the loop, first determine whether the current thread is interrupted , If it has been interrupted , Call removeWaiter() Remove the current thread from the stack , And throw InterruptedException abnormal , As shown below .
if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException();}Next , Determine whether the current state of the task is complete , If completed , And the stack handle is not empty , Set the current thread in the stack to null , Returns the status of the current task , As shown below .
int s = state;if (s > COMPLETING) { if (q != null) q.thread = null; return s;}When the state of the task is COMPLETING when , Make the current thread out CPU resources , As shown below .
else if (s == COMPLETING) Thread.yield();If the stack is empty , Then create a stack object , As shown below .
else if (q == null) q = new WaitNode();If queued Variable is false, adopt CAS Operation for queued assignment , If awaitDone() Method delivered timed Parameter is true, The timeout is calculated , When the time has expired , Remove the current thread from the stack and return to the task state , As shown below . If it doesn't time out , Reset the timeout , As shown below .
else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos);}If all the above conditions are not met , Set the current thread to wait state , As shown below .
else LockSupport.park(this);Next , go back to get() In the method , When awaitDone() Method returns the result , Or when the state of the task does not meet the condition , Will be called report() Method , And pass the status of the current task to report() In the method , And return the result , As shown below .
return report(s);It seems , Here's another look report() Methods: , Go in and have a look report() Method implementation , As shown below .
private V report(int s) throws ExecutionException { Object x = outcome; if (s == NORMAL) return (V)x; if (s >= CANCELLED) throw new CancellationException(); throw new ExecutionException((Throwable)x);}You can see ,report() Method implementation is relatively simple , First , take outcome The data is assigned to x Variable , Next , It is mainly to judge the received task status , If the state is NORMAL, Will x Strong conversion to generic type returns ; When the state of the task is greater than or equal to CANCELLED, That is, the mission has been cancelled , Throw out CancellationException abnormal , In other cases ExecutionException abnormal .
thus ,get() Method analysis completion . Be careful : Be sure to understand get() Method implementation , because get() The way is that we use Future Interface and FutureTask Class time , A more frequently used method .
(6)set() Methods and setException() Method
Continue to look at FutureTask Class code , What we see next is set() Methods and setException() Method , As shown below .
protected void set(V v) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { outcome = v; UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state finishCompletion(); }}protected void setException(Throwable t) { if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { outcome = t; UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state finishCompletion(); }}You can see from the source code ,set() Methods and setException() The overall logic of the method is almost the same , It's just that when you set the task state, you can set the state to NORMAL, One sets the state to EXCEPTIONAL.
as for finishCompletion() Method , I've analyzed .
(7)run() Methods and runAndReset() Method
Next , Namely run() The method ,run() The source code for the method is as follows .
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); }}You can say that , Just use Future and FutureTask, It's bound to call run() Method to run the task , master run() Method flow is very necessary . stay run() In the method , If the current state is not NEW, perhaps CAS The result returned by the operation is false, Then return directly , No more subsequent logic , As shown below .
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return;Next , stay try Block of code , Member variable callable Assign a value to a temporary variable c, Judge that the temporary variable is not equal to null, And the task status is NEW, Call Callable Interface call() Method , And receive the result data . And will ran The variable is set to true. When the program throws an exception , Set the variable that receives the result to null,ran The variable is set to false, And call setException() Method to set the state of the task to EXCEPTIONA. Next , If ran Variable is true, Call set() Method , As shown below .
try { Callable<V> c = callable; if (c != null && state == NEW) { V result; boolean ran; try { result = c.call(); ran = true; } catch (Throwable ex) { result = null; ran = false; setException(ex); } if (ran) set(result); }}Next , The program will enter finally Block of code , As shown below .
finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts int s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s);}here , take runner Set to null, If the current state of the task is greater than or equal to INTERRUPTING, That is, the thread is interrupted . Call handlePossibleCancellationInterrupt() Method , Next , look down handlePossibleCancellationInterrupt() Method implementation .
private void handlePossibleCancellationInterrupt(int s) { if (s == INTERRUPTING) while (state == INTERRUPTING) Thread.yield();}You can see ,handlePossibleCancellationInterrupt() Method implementation is relatively simple , When the state of the task is INTERRUPTING when , Use while() loop , The condition is that the current task status is INTERRUPTING, Will be occupied by the current thread CPU Release resources , in other words , When the task is finished , Release resources occupied by threads .
runAndReset() The logic of the method and run() almost , It's just runAndReset() Methods in finally The code block resets the task state to NEW.runAndReset() The source code for the method is as follows , Don't repeat .
protected boolean runAndReset() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return false; boolean ran = false; int s = state; try { Callable<V> c = callable; if (c != null && s == NEW) { try { c.call(); // don't set result ran = true; } catch (Throwable ex) { setException(ex); } } } finally { // runner must be non-null until state is settled to // prevent concurrent calls to run() runner = null; // state must be re-read after nulling runner to prevent // leaked interrupts s = state; if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } return ran && s == NEW;}(8)removeWaiter() Method
removeWaiter() The main method is to use spin loop to remove WaitNode Thread in , Relatively simple , As shown below .
private void removeWaiter(WaitNode node) { if (node != null) { node.thread = null; retry: for (;;) { // restart on removeWaiter race for (WaitNode pred = null, q = waiters, s; q != null; q = s) { s = q.next; if (q.thread != null) pred = q; else if (pred != null) { pred.next = s; if (pred.thread == null) // check for race continue retry; } else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s)) continue retry; } break; } }}Last , stay FutureTask The end of the class , There are the following codes .
// Unsafe mechanicsprivate static final sun.misc.Unsafe UNSAFE;private static final long stateOffset;private static final long runnerOffset;private static final long waitersOffset;static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> k = FutureTask.class; stateOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("state")); runnerOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("runner")); waitersOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("waiters")); } catch (Exception e) { throw new Error(e); }}About what these codes do , It will be analyzed in depth later CAS The article details , I won't discuss it here .
thus , About Future Interface and FutureTask The source code of the class is analyzed .
About Java Medium Callable and Future, After reading this article, I'm no longer afraid of the interviewer , Everybody, feel free to ask !!
Okay , That's all for today , I'm glacier , If you have any questions, please leave a message below ,, Exchange technology together , Step up together , Go into the big factory together ~~
边栏推荐
- Write it down once Net analysis of a property management background service stuck
- Interpretation of RESNET source code in mmdet +ghost module
- Koa2+better-sqlite3 to add, delete, change and query
- 维修记录导出的excel表格太大怎么办?
- Follow me study hcie big data mining Chapter 1 Introduction to data mining module 2
- How to install MySQL 8.0 on rocky Linux and almalinux
- Three best practices help enterprises improve supply chain security
- 超 Nice 的表格响应式布局小技巧
- 使用 Gerrit + Zadig 实现主干开发主干发布(含字节飞书实践)
- Introduction to reverse commissioning -pe file section table and block 03/07
猜你喜欢

Cloud native (31) | kubernetes chapter kubernetes platform basic pre installed resources

Why is the integration of storage and computing a new direction of core making Collision school x Zhicun Technology

深度学习的坎坷六十年

matplotlib的imshow函数显示灰度图像要设置vmin和vmax2个参数

云原生(三十一) | Kubernetes篇之Kubernetes平台基本预装资源

丢弃 Tkinter!简单配置快速生成超酷炫 GUI!

揭秘!付费会员制下的那些小心机!

使用 Gerrit + Zadig 实现主干开发主干发布(含字节飞书实践)

Yyds dry inventory solution sword finger offer: find the nearest common ancestor of two nodes in the binary tree

Problems in replacing RESNET convolution of mmdet with ghost convolution group
随机推荐
C keyboard hook
PG Basics - logical structure management (1)
Memorized Function
Why is the integration of storage and computing a new direction of core making Collision school x Zhicun Technology
Follow me study hcie big data mining Chapter 1 Introduction to data mining module 1
iMile 利用 Zadig 多云环境周部署千次,跨云跨地域持续交付全球业务
Weserver publishing map service
Equivalence class partition method for test case design method
[graduation season] it's worth it all the way over the past four years -- advice from the senior students
Want to make a wechat game for answering questions? Reading this article is enough
#yyds干货盘点# 解决剑指offer:在二叉树中找到两个节点的最近公共祖先
System. Currenttimemillis() and system Nanotime() which is faster? Most people get the wrong answer!
Leetcode question brushing: String 07 (repeated substring)
The node command in the script does not print the execution log on the console
Why does ETL often become ELT or even let?
技术分享| 融合调度中的广播功能设计
Sixty years of deep learning
Cicd introduction [easy to understand]
June training (day 29) - divide and rule
灵感收集·创意写作软件评测:Flomo、Obsidian Memo、Napkin、FlowUs