preface
Today is 1024. I wish all bosses a happy holiday!
I'm going to go downstairs to buy some food in the evening. I'm determined to pay attention. I'm going to buy [egg] and [hand grasping cake] tonight. Good guy, there's no material. Hey, hey!
So I set out with the pace of "six relatives do not recognize"
Can you hurry up
❓ On the way, I thought about a problem. That is, how long does it take me to grasp simple happiness?
According to the process, it's like this
- Ride my beloved little motorcycle
- Arrive at the egg stall, order an egg, and wait for the boss to finish
- Then go to the hand cake stall and order a hand cake
- Grab the cake and ride home
Suppose the round trip is 6 minutes, the time for making eggs is 10 minutes, and the time for making hand grabbing cakes is 5 minutes
Then I need a total of [21] minutes before I can sit by the computer, watch a play and cook
If you want to shorten the time, the above process is not what we need, but should be like this
- Ride my beloved little motorcycle
- Arrive at the egg stall, order an egg and tell the boss I'll get it later
- Then go to the hand cake stall and order a hand cake
- After getting the cake, return to the egg stall and wait for the egg
- go home by bicycle
At this time, our time is only [16] minutes, because this time after I ordered the eggs, the boss first completed an operation that took less than 10 minutes during the cooking period, that is, to buy the hand grabbing cake I want
Of course, I must use the second way...
Land
Sort out the process just now
- The first process is typical, which is executed in sequence
- The second process uses the idea of asynchrony
Then you might as well knock down the code and show the process
First, we have to have someone to buy food
/** * @Author: Amg * @Date: Created in 20:22 2021/10/24 * @Description: Construct "buy something to eat" object */ public class BuySomethingToEat { /** * Food name */ private String foodName; /** * Production duration unit */ private TimeUnit unit; /** * Production time */ private Long waitSecond; public BuySomethingToEat(String foodName, TimeUnit unit, Long waitSecond) { this.foodName = foodName; this.unit = unit; this.waitSecond = waitSecond; } @Override public String toString() { return new StringJoiner(", ", BuySomethingToEat.class.getSimpleName() + "[", "]") .add("foodName='" + foodName + "'") .add("unit=" + unit) .add("waitSecond=" + waitSecond) .toString(); } /** * Processing ingredients * @return */ public String handlerFood() { System.out.println(String.format("Food is being prepared:[%s],Company:[%s],Waiting time:[%s] ",foodName,waitSecond,unit.toString())); try { unit.sleep(waitSecond); } catch (InterruptedException e) { e.printStackTrace(); } return this.toString() + " is done!"; } }
Follow the idea of order
/** * @Author: Amg * @Date: Created in 21:09 2021/10/24 * @Description: Conventional practice */ public class Convention { public static void main(String[] args) throws Exception { final long start = System.currentTimeMillis(); //We can't have time to really wait for 10 minutes, so we use seconds instead final BuySomethingToEat eatOne = new BuySomethingToEat("egg puffs", TimeUnit.SECONDS, 10L); final BuySomethingToEat eatTwo = new BuySomethingToEat("shredded pancake", TimeUnit.SECONDS, 5L); System.out.println(eatOne.handlerFood()); System.out.println(eatTwo.handlerFood()); System.out.println("I bought it all,Go home!"); //Finally, add six minutes back and forth System.out.println("Total time:" + ((System.currentTimeMillis() - start) / 1000 + 6)); } } //output Food is being prepared:[egg puffs],Company:[10],Waiting time:[SECONDS] BuySomethingToEat[foodName='egg puffs', unit=SECONDS, waitSecond=10] is done! Food is being prepared:[shredded pancake],Company:[5],Waiting time:[SECONDS] BuySomethingToEat[foodName='shredded pancake', unit=SECONDS, waitSecond=5] is done! I bought it all,Go home! Total time: 15
Execute according to the idea of asynchrony
Asynchronous thinking
Before introducing today's protagonist, let's understand the idea of asynchrony, or let's start with a diagram
The asynchronous idea is: when you are ready, tell me. I'll do other things first
As shown in the corresponding figure, in the process of making eggs, I won't wait here because it takes a long time. I'll grab some cakes first (complete other operations that don't take that long)
Today's pig's feet, the Future model in jdk
Because the Future pattern (the core idea is asynchronous call) is very common, the JDK has prepared the implementation for us
In short, through Future, you can define a task and let it execute. At some time in the Future, you can obtain data through the API. If you can't obtain it, it will be blocked all the time
//There are five methods in the Future interface. Would you like to know more? Just read the interface documentation directly 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; }
This is an interface, and what we really use is its subclass FutureTask
Let's look at the FutureTask class
It can be found that his construction method needs to pass in a class that implements Callable or Runnable. In that case, let's create another BuyTask
/** * @Author: Amg * @Date: Created in 21:15 2021/10/24 * @Description: TODO */ public class BuyTask implements Callable<String> { private BuySomethingToEat buySomethingToEat; public BuyTask(BuySomethingToEat buySomethingToEat) { this.buySomethingToEat = buySomethingToEat; } @Override public String call() throws Exception { return buySomethingToEat.handlerFood(); } }
Then, use the FutureTask class to create two tasks to be executed by the thread pool
public class MyFutureTask { public static void main(String[] args) throws ExecutionException, InterruptedException { final BuySomethingToEat eatOne = new BuySomethingToEat("shredded pancake", TimeUnit.SECONDS, 10L); final BuySomethingToEat eatTwo = new BuySomethingToEat("egg puffs", TimeUnit.SECONDS, 5L); final long start = System.currentTimeMillis(); ExecutorService executorService = Executors.newFixedThreadPool(2); final FutureTask<String> task1 = new FutureTask<>(new BuyTask(eatOne)); final FutureTask<String> task2 = new FutureTask<>(new BuyTask(eatTwo)); executorService.submit(task1); executorService.submit(task2); System.out.println(task2.get()); System.out.println(task1.get()); System.out.println("I bought it all"); System.out.println("Total time:" + (System.currentTimeMillis() - start) / 1000); if (!executorService.isShutdown()) executorService.shutdown(); } } //output Food is being prepared:[egg puffs],Company:[5],Waiting time:[SECONDS] Food is being prepared:[shredded pancake],Company:[10],Waiting time:[SECONDS] BuySomethingToEat[foodName='egg puffs', unit=SECONDS, waitSecond=5] is done! BuySomethingToEat[foodName='shredded pancake', unit=SECONDS, waitSecond=10] is done! I bought it all Total time: 16 //Or Food is being prepared:[shredded pancake],Company:[10],Waiting time:[SECONDS] Food is being prepared:[egg puffs],Company:[5],Waiting time:[SECONDS] BuySomethingToEat[foodName='egg puffs', unit=SECONDS, waitSecond=5] is done! BuySomethingToEat[foodName='shredded pancake', unit=SECONDS, waitSecond=10] is done! I bought it all Total time: 16
summary
The Future model has a wide range of uses
- Common are SQL asynchronous calls. When a SQL takes a little longer, you can first execute other steps that are not related to the SQL process to save time;
- There are also computationally intensive operations
- There are also asynchronous calls to other system interfaces
There are more advanced uses for Future. At present, I just briefly introduce how Future and its implementation class FutureTask are used, which is enough for understanding the idea of Future and simple use
However, there will be more advanced usage of Future, such as the enhancement of Future in guava, which will be further introduced later