In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the knowledge of "how to understand the Future of asynchronous programming". Many people will encounter such a dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Let's talk about how the thread pool is submitted.
When we talk about Future, we basically think of thread pools and several of its commit methods.
First, it is the simplest. If you submit it in execute mode, if you don't care about the return value, throw the task directly into the thread pool and finish the task:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ThreadPoolExecutor executor = new ThreadPoolExecutor (2, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue (10)); / / execute (Runnable command) method. No return value executor.execute (()-> {System.out.println ("focus on why technology");}); Thread.currentThread () .join ();}}
You can take a look at the execute method and accept a Runnable method with the return type void:
Then there is the submit method. Do you know how many submit methods there are in thread pools?
Although you often use it, you may never care about others. Bah, scumbag:
There are three submit types. These three are divided into two types according to the type of task submitted.
Commit to execute a task of type Runnable.
Commit to execute a task of type Callable.
But the return values are all Future, and that's what we care about.
Maybe you know that there are three submit methods in the thread pool, but maybe you don't even know that there are two types of tasks in the thread pool, and you just throw them into the thread pool, no matter what type of task is thrown.
Let's first take a look at how Callable-type tasks are performed:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ThreadPoolExecutor executor = new ThreadPoolExecutor (2,5,60, TimeUnit.SECONDS, new LinkedBlockingQueue (10)); Future future = executor.submit (()-> {System.out.println ("focus on why technology"); return "definitely this time!" ;}); System.out.println ("content of future:" + future.get ()); Thread.currentThread (). Join ();}}
Here, using the lambda expression, you directly put a return value in the task body, and then the method you call becomes this:
The running results can also be returned in the task body. The output is as follows:
OK, let's talk about the situation where the task of submit is of type Runable.
There are two forms of overloading at this time:
The method labeled ① throws in a Runable task and returns a Future, and this return Future is equivalent to returning a loneliness. I'm going to talk about why.
The method labeled ② throws a Runable task and then a generic T, and the generics in the returned Future are also T, so let's make a bold guess that this is the same object. If it is the same object, it means that we can pass an object to the task body for operation, and then get the object again through Future. I'll check it out in a minute.
Come on, first verify the method labeled ①, why do I say it returns a loneliness.
First, put the test case here:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ThreadPoolExecutor executor = new ThreadPoolExecutor (2,5,60, TimeUnit.SECONDS, new LinkedBlockingQueue (10)); Future future = executor.submit (()-> {System.out.println ("focus on why technology"); System.out.println ("content of future:" + future.get ()); Thread.currentThread (). Join () }}
As you can see, it is indeed the method labeled ① that is called:
At the same time, we can see that the return value of the future.get () method is null.
You say, this is not a return to a lonely what is it?
When you want to use the method labeled ①, I advise you to submit the task directly in execute. There is no need to build a lonely return value, only adding useless objects.
Next, let's look at how the method labeled ② works:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ThreadPoolExecutor executor = new ThreadPoolExecutor (2,5,60, TimeUnit.SECONDS, new LinkedBlockingQueue (10)); AtomicInteger atomicInteger = new AtomicInteger (); Future future = executor.submit (()-> {System.out.println ("focus on why technology"); / / Computational logic atomicInteger.set (5201314) here }, atomicInteger); System.out.println ("content of future:" + future.get ()); Thread.currentThread () .join ();}}
You can see that after the modification, the method labeled ② is indeed called:
The output of the future.get () method is also 5201314 of what we calculated in the asynchronous task.
You see, that's what a scumbag is like. He doesn't understand you, but he has to bomb you with sweet words. Bah.
Okay. To sum up, there are four ways to submit a thread pool: an execute with no return value. There are three kinds of submit, with return values.
Submit is divided into two types according to the type of submitted task: one is Callable, the other is Runable.
There are two overloaded methods for the task type of Runable in submit: one returns a loneliness and the other returns a scumbag. Oh, no. One returns a loneliness, the other returns an object.
At this time, someone is going to come forward and say: what you said is wrong, you are talking nonsense, obviously there is only one way to submit execute.
Yes, the statement that "only execute is the only way to submit" is also true.
Please look at the source code:
The execute method is called in all three submit methods.
To be able to explain the above methods, from the surface to the inner, is a good person.
Only if I love you will I study you thoroughly.
Of course, there are these submission methods, which are not used much, so we won't talk about them:
All right, after all these things are sorted out. Let's focus on the return value Future:
We can see from the above code that when we want to return a value, we need to call the following get () method:
From the description of this method, we can see that this is a blocking method. If you don't get the value, just wait there. Of course, there is also a get method with a timeout, which will not wait after the specified time.
Bah, scumbag. Without patience, I can't bear to wait for this time.
Anyway, we might have to wait. Just wait, then it's blocking. As long as it is blocking, it is a pseudo async.
So summarize the shortcomings of the Future returned in this scenario:
Only the get method is actively called to get the value, but it is possible to block the wait before the value is ready.
When an exception occurs during task processing, the exception is hidden and encapsulated in Future, and the exception is known only when the get method is called.
When I write here, I can't help but think of an example of an image. I'll give you one.
Suppose you want to ask your goddess to dinner. As for the goddess, she must wear beautiful makeup before she goes shopping. The goddess's makeup can be compared to an asynchronous task we submitted.
Suppose you are a small loser, then the goddess will say to you: I have already started to put on makeup, call me when you get downstairs.
Then you pack up and get ready to go, which means you can do something of your own after you submit the asynchronous task.
It took you an hour to get to the goddess downstairs and call her: Hello, goddess, I'm downstairs.
The goddess said, "wait a minute. I haven't finished my makeup yet."
So you start waiting, waiting endlessly. This is the future.get () method with no timeout.
It is also possible for you to be tough and say to the goddess, "I'll wait 24 hours at the most. If I don't go downstairs for more than 24 hours, I'll go."
This is the future.get (timeout,unit) method with timeout:
And 24 hours later, before the goddess came down, you left.
Of course, there is also a situation where you go downstairs and call the goddess, and the goddess says, "Hey, today my male god asked me out to see a movie, so I won't go to dinner with you." I wanted to tell you in advance, but I can't remember your number. I can only tell you when you call. That's it. Go play by yourself.
This is equivalent to throwing an exception during the execution of an asynchronous task, and you don't know the original exception until you call the get method (call operation).
And the real asynchronous is that you don't have to wait for me, I'll call you when I'm ready.
As the goddess said when she received the call from the male god: I need a little time to prepare, you play with your own first, I will call you when I am ready.
This reminds me of the Hollywood principle: Don't Call Us,We'll Call you!
Next, let's take a look at true asynchronism.
What is real: "you play with your own first, and I'll call you when I'm ready."
Future of Guava
The goddess said, "I'll call you when you're ready".
It is a callback mechanism. Speaking of callbacks, we just need to register a callback function after the asynchronous task has been submitted.
Future for JDK is extended in the Guava package provided by Google:
A new addListenter method has been added with input parameters of a Runnable task type and a thread pool.
To use the method, first look at the code:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ListeningExecutorService executor = MoreExecutors.listeningDecorator (Executors.newCachedThreadPool ()); ListenableFuture listenableFuture = executor.submit (()-> {System.out.println (Thread.currentThread (). GetName () + "- Goddess: I'm starting to make up, I'll call you.") ; TimeUnit.SECONDS.sleep (5); return "the makeup is done." ;}); listenableFuture.addListener (()-> {try {System.out.println (Thread.currentThread (). GetName () + "- future content:" + listenableFuture.get ());} catch (Exception e) {e.printStackTrace ();}}, executor) System.out.println (Thread.currentThread (). GetName () + "- wait for the goddess to do her own thing when she wears makeup.") ; Thread.currentThread (). Join ();}
First, the way to create a thread pool has changed, and you need to decorate it with the MoreExecutors method in Guava:
ListeningExecutorService executor = MoreExecutors.listeningDecorator (Executors.newCachedThreadPool ())
Then call the submit method (either) with the decorated executor, and return ListenableFuture. Once we get the ListenableFuture, we can register the listener on it:
So, in the above program, we call the interface whose input parameter is of type callable:
It can be seen from the run result that the run result is executed in another thread and does not block the main thread at all.
It is still very different from the previous "pseudo-async".
In addition to the addListener method above, I actually prefer to use the FutureCallback approach.
You can take a look at the code, which is very intuitive:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {ListeningExecutorService executor = MoreExecutors.listeningDecorator (Executors.newCachedThreadPool ()); ListenableFuture listenableFuture = executor.submit (()-> {System.out.println (Thread.currentThread (). GetName () + "- Goddess: I'm starting to make up, I'll call you.") ; TimeUnit.SECONDS.sleep (5); return "the makeup is done." ;}); Futures.addCallback (listenableFuture, new FutureCallback () {@ Override public void onSuccess (@ Nullable String result) {System.out.println (Thread.currentThread (). GetName () + "- future content:" + result) } @ Override public void onFailure (Throwable t) {System.out.println (Thread.currentThread (). GetName () + "- the goddess stood you up.") ; t.printStackTrace ();}}); System.out.println (Thread.currentThread (). GetName () + "- wait for the goddess to do her own thing when she wears makeup.") ; Thread.currentThread (). Join ();}
There are onSuccess methods and onFailure methods.
The output of the above program is:
If an exception is thrown during the execution of an asynchronous task, for example, if the goddess is asked out by her male god, the asynchronous task will be changed to this:
ListenableFuture listenableFuture = executor.submit (()-> {System.out.println (Thread.currentThread (). GetName ()) + "- Goddess: I'm starting to make up. I'll call you when I'm ready.") ; TimeUnit.SECONDS.sleep (5); throw new Exception ("if the male god asks me to see a movie, he won't have dinner with you.") ;})
The final running result is as follows:
Yes, the goddess has gone to the cinema. She must just don't want to eat.
Enhanced version of Future-CompletableFuture
The Future in the first section is a product of the JDK 1.5 era:
After so many years of development, Doug Lea introduced a new CompletableFuture in JDK 1.8:
In the era of JDK 1.8, this is the real asynchronous programming.
CompletableFuture implements two interfaces, one is the familiar Future, and the other is CompletionStage.
CompletionStage interface. You can see that there is a Stage in the name of this interface:
This interface can be understood as a stage of a task. So multiple CompletionStage links together is a chain of tasks. After the previous task is completed, the next task is automatically triggered.
There are a lot of methods in CompletableFuture.
Because of the space, I will demonstrate only one method:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {CompletableFuture completableFuture = CompletableFuture.supplyAsync (()-> {System.out.println (Thread.currentThread (). GetName () + "- Goddess: I'm starting to make up, I'll call you when I'm ready.") ; try {TimeUnit.SECONDS.sleep (5);} catch (InterruptedException e) {e.printStackTrace ();} return "makeup is done." ;}); completableFuture.whenComplete ((returnStr, exception)-> {if (exception = = null) {System.out.println (Thread.currentThread (). GetName () + returnStr);} else {System.out.println (Thread.currentThread (). GetName () + "the Goddess stood you up.") ; exception.printStackTrace ();}}); System.out.println (Thread.currentThread (). GetName () + "- wait for the goddess to do her own thing when she wears makeup.") ; Thread.currentThread (). Join ();}
The execution result of this method is as follows:
We didn't specify which thread pool to use when we executed, but we can see from the result that the execution is also asynchronous.
As you can see from the output log, ForkJoinPool.commonPool () is the thread pool it uses by default.
Of course, we can also specify it ourselves.
This method is widely used in many open source frameworks.
Next, let's take a look at CompletableFuture's handling of exceptions. I think it's very elegant.
There is no need for a try-catch code block wrapper or a call to Future.get () to know the exception, which provides a handle method that handles exceptions that occur in upstream asynchronous tasks:
Public class JDKThreadPoolExecutorTest {public static void main (String [] args) throws Exception {CompletableFuture.supplyAsync ()-> {System.out.println (Thread.currentThread (). GetName () + "- Goddess: I'm starting to make up, I'll call you when I'm ready.") ; throw new RuntimeException ("the male god asked me to see a movie. Let's do it next time. You are a good man.") ) .handleAsync ((result, exception)-> {if (exception! = null) {System.out.println (Thread.currentThread (). GetName () + "- the goddess stood you up!") ; return exception.getCause ();} else {return result;}}) .thenApplyAsync ((returnStr)-> {System.out.println (Thread.currentThread (). GetName () + "-" + returnStr); return returnStr;}) System.out.println (Thread.currentThread (). GetName () + "- wait for the goddess to do her own thing when she wears makeup.") ; Thread.currentThread (). Join ();}
As the goddess was wearing makeup, she received a call from the male god to ask her to see a movie, so she had to stand you up.
So, the output of the above program is as follows:
If you successfully ask the goddess out, it goes like this:
That's all for "how to understand the Future of Asynchronous programming". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.