Java executes code asynchronously (returns the result first, then executes the code

Business scene:

        After the user or role is changed, the data must be updated, because the update takes a long time, and the result needs to be returned first (2: Received and pending execution). After the update is complete, return the value result.

(Execution result. 0: Execution failed; 1: Execution succeeded; 2: Received and pending execution)

Processing 1: Simple asynchronous

Asynchronous using ExecutorService

    public void onCallback(JSONObject param) {
        ExecutorService executor = Executors.newCachedThreadPool();
        executor.execute(() -> {
            try {
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 这边执行具体的方法
            this.syncDealResult(param);

        });
        executor.shutdown();
    }

    public JSONObject dealResult(JSONObject params) {
        // 先返回结果,然后异步执行
        this.onCallback(params);
        JSONObject result = new JSONObject();
        result.put("excRs", "2");
        return result;
    }
 

    public void syncDealResult(JSONObject params) {
        logger.info("deal abRole param {}", JSON.toJSONString(params));
        String logId = MapUtils.getString(params, "logId");
        String excRs = "1";
        try {
            // 具体操作
        } catch (Exception e) {
            e.printStackTrace();
            excRs = "-1";
        }
        logger.info("update abRole finish callRecordId {}, excRs {}", logId, excRs);
        // 处理完后推送结果
        JSONObject param = new JSONObject();
        param.put("logId", logId);
        param.put("excRs", excRs);
        // 推送结果
    }

Add Thread.sleep(1000 * 10); You can clearly see the difference.

If there are multiple asynchronous executions, for example: after A is executed, B needs to be notified; C needs to be stored in the warehouse; D needs to be counted, how should we deal with it at this time?

Processing 2: multiple asynchronous executions

IRoleCallback

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;

/**
 * AB角色异步调用接口
 *
 */
public interface IRoleCallback {

    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @param param 结果
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    Object call(JSONObject param) throws Exception;

    /**
     * unique name of callback
     *
     * @return callback name
     */
    default String name() {
        return StringUtils.uncapitalize(getClass().getSimpleName());
    }

    /**
     * prior to callback 用于排序
     *
     * @return order
     */
    default double order() {
        return 1.0d;
    }

}

RoleCallbackRegister

import java.util.*;

public class RoleCallbackRegister {
    private static final Map<String, IRoleCallback> CALLBACKS = new HashMap<>();

    public static boolean register(IRoleCallback callback) {
        if (CALLBACKS.containsKey(callback.name())) {
            return false;
        }
        CALLBACKS.put(callback.name(), callback);
        return true;
    }

    public static List<IRoleCallback> getCallbacks() {
        List<IRoleCallback> roleCallbacks = new ArrayList<>(CALLBACKS.values());
        roleCallbacks.sort(Comparator.comparingDouble(IRoleCallback::order));
        return roleCallbacks;
    }
}

SpringUtils

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
}

AbstractRoleCallbackImpl

import com.web.work.common.support.SpringUtils;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

public abstract class AbstractRoleCallbackImpl implements IRoleCallback, InitializingBean {
    protected final Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public Object call(JSONObject param) throws Exception {
        return doCall(param);
    }

    protected abstract Object doCall(JSONObject param) throws Exception;

    @Override
    public String name() {
        return StringUtils.uncapitalize(getClass().getSimpleName());
    }

    @Override
    public void afterPropertiesSet() {
        boolean register = RoleCallbackRegister.register(SpringUtils.getBean(this.getClass()));
        if (!register) {
            logger.error("register role callback name:{} failed.", name());
        } else {
            logger.info("register role callback name:{} succeed.", name());
        }
    }
}

RoleCallBackService

@Service
public class RoleCallBackService implements InitializingBean, DisposableBean {

    private final static Logger logger = LoggerFactory.getLogger(RoleCallBackService.class);

    private ThreadPoolExecutor pool;

    public void onCallback(JSONObject param) {
        pool.execute(() -> {
            RoleCallbackRegister.getCallbacks().forEach(x -> {
                try {
                    logger.info("call {}", x.name());
                    x.call(param);
                } catch (Exception e) {
                    logger.error("回调{}接口失败:", x.name(), e);
                }
            });
        });
    }

    @Override
    public void afterPropertiesSet() {
        int size = Runtime.getRuntime().availableProcessors() + 1;
        pool = new ThreadPoolExecutor(size, size * 2, 300L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
    }

    @Override
    public void destroy() throws Exception {
        pool.shutdown();
    }
}

RoleUpdateService

@Service
public class RoleUpdateService extends AbstractRoleCallbackImpl {

    private final static Logger logger = LoggerFactory.getLogger(RoleUpdateService.class);

    @Override
    protected Object doCall(JSONObject params) throws Exception {
        Thread.sleep(1000 * 10);
        logger.info("deal abRole param {}", JSON.toJSONString(params));
        String logId = MapUtils.getString(params, "logId");
        String excRs = "1";
        try {
            // 执行更新操作
        } catch (Exception e) {
            e.printStackTrace();
            excRs = "-1";
        }
        logger.info("update abRole finish callRecordId {}, excRs {}", logId, excRs);
        // 处理完后推送结果
        JSONObject param = new JSONObject();
        param.put("logId", logId);
        param.put("excRs", excRs);
        logger.info("update role record {}", JSON.toJSONString(param));
        // 推送结果
        return "";
    }
}

Execute after returning the result first

    @Resource
    private RoleCallBackService roleCallBackService;

    public JSONObject dealResult(JSONObject params) {
        // 先返回结果,然后异步执行
        try {
            roleCallBackService.onCallback(params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        JSONObject result = new JSONObject();
        result.put("excRs", "2");
        return result;
    }

Summarize:

        To return the result first, then execute the content, you need to use an asynchronous method and use ExecutorService for processing. If it is single, it is simpler to call directly. If there are more than one, they must be registered first, and then traversed to call. 

Guess you like

Origin blog.csdn.net/qq_35461948/article/details/130762448