Use of Future pattern in Java

Posted by pmeasham on Sun, 24 Oct 2021 17:07:02 +0200

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

  1. Ride my beloved little motorcycle
  2. Arrive at the egg stall, order an egg, and wait for the boss to finish
  3. Then go to the hand cake stall and order a hand cake
  4. 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

  1. Ride my beloved little motorcycle
  2. Arrive at the egg stall, order an egg and tell the boss I'll get it later
  3. Then go to the hand cake stall and order a hand cake
  4. After getting the cake, return to the egg stall and wait for the egg
  5. 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

Topics: Java