@Async注解实现异步任务

        我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线程池。

        默认情况下,Spring将搜索相关的线程池定义:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名为“taskExecutor”的Executor bean。如果两者都无法解析,则将使用SimpleAsyncTaskExecutor来处理异步方法调用。

        基于@Async标注的方法称为异步方法,方法在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。使用时在SpringBoot主配置类中开启异步即可。

        @Async注解来声明一个或多个异步任务,可以加在方法或者类上,加在类上表示这整个类都是使用这个自定义线程池进行操作

如下方式会使@Async失效
一、异步方法使用static修饰
二、异步类没有使用@Component注解(或其他注解)导致spring无法扫描到异步类
四、类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
五、如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
六、在Async 方法上标注@Transactional是没用的。 在Async 方法调用的方法上标注@Transactional 有效。
七、调用被@Async标记的方法的调用者不能和被调用的方法在同一类中,因为@Async注解是通过aop代理实现的,视为内部调用!!!!!!!如果非要在一个bean中,使用代理获得当前class的bean后,使用bean调用被标识的方法。
八、使用@Async时要求是不能有返回值的不然会报错的 因为异步要求是不关心结果的

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class AsyncDemoApplication {

    /**
     * 异步方法
     *
     * @throws InterruptedException
     */
    @Async
    public void asyncMethod() throws InterruptedException {
        for (int i = 1; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "********" + i);
        }
    }

    public static void main(String[] args) {

        try {
            //获取上下文
            ConfigurableApplicationContext context = SpringApplication.run(AsyncDemoApplication.class, args);

            //获取对象bean,进而调用异步方法
            context.getBean(AsyncDemoApplication.class).asyncMethod();
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "********" + i);
                if (2 == i)
                    Thread.sleep(1000l);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


@EnableAsync
@SpringBootApplication
public class SpringBootAsyncTestApplication {

}

无返回值异步方法
@Async
public void asyncMethodWithNoReturnType() {
    try {
        Thread.sleep(3000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("asyncMethodWithNoReturnType...");
}

含返回值异步方法
@Async
public Future<String> asyncMethodWithReturnType() {
   try {
   		Thread.sleep(3000);
   		return new AsyncResult<String>("success");
   } catch (InterruptedException e) {
   		e.printStackTrace();
   }
   System.out.println("asyncMethodWithReturnType...");
   return null;
}

 Future是对于具体的 Runnable 或者 Callable 任务的执行结果进行取消、查询是否完成、获取结果的接口,必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果,包含了以下几个方法。

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;
}

1.cancel方法的作用是取消任务,取消任务成功则返回true,反之返回false。参数 mayInterruptIfRunning 表示是否允许取消正在执行却没有执行完毕的任务。

运行cancel方法取消任务时:

i.若任务已完成:则无论 mayInterruptIfRunning 为 true 或 false,此方法都返回 false,即取消已经完成的任务都会返回false。

i.若任务正在执行:

mayInterruptIfRunning 设置为 true,则返回true。

mayInterruptIfRunning 设置为false,则返回false。

iii.如果任务未执行,则无论mayInterruptIfRunning为true还是false,都返回true。

2.isCancelled方法的作用是判断任务是否被取消成功,若在任务正常完成前被取消,则返回 true。

3.isDone方法的作用是判断任务是否已经完成,若任务已完成,则返回true。

4.get()方法的作用是获取执行结果,注意此方法会产生阻塞,等到任务执行完毕后才能获得执行结果。

5.get(long timeout, TimeUnit unit)方法的作用同样是获取执行结果,若在指定时间内还未获取到执行结果,则返回null。

Future提供了三种功能:

  • 判断任务是否完成
  • 能够中断任务
  • 能够获取任务执行结果
@RestController
public class AsyncController {
    @Autowired
    AsyncService asynSerivce;

    @GetMapping("/callWithNoReturnType")
    public String callWithNoReturnType() {
        asynSerivce.asyncMethodWithNoReturnType();
        return "success";
    }

    @GetMapping("/callWithReturnType")
    public String callWithReturnType() {
        Future<String> future=asynSerivce.asyncMethodWithReturnType();
        try {
            return future.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return "fail";
    }

调用无返回值的异步方法asyncWithNoReturnType时,会立即返回返回值。但调用含返回值异步方法asyncWithReturnType时,由于我们调用了get()方法,会在等待3000毫秒后,才返回返回值。

加上@Transactional后,feign远程调用超时的问题可能与事务的提交时间有关。一旦使用@Transactional注解,Spring将整个方法包装在一个事务中,这意味着如果其中的某个feign远程调用耗时较长,整个事务也被延长。因此,如果feign远程调用存在超时问题,可能导致事务无法在规定时间内完成提交。 为了解决这个问题,有几种方法可以尝试: 1. 调整事务的超时时间:可以通过在@Transactional注解中设置timeout属性来调整事务的超时时间,以适应feign远程调用的耗时。 2. 异步处理:可以将feign远程调用改为异步处理,这样可以避免阻塞主线程。可以使用Spring提供的@Async注解远程调用方法标记为异步执行。 3. 使用独立的事务管理:可以考虑将feign远程调用的方法放在独立的事务管理中,而不将其包含在主事务中。可以使用编程式事务手动控制事务范围,而不使用声明式事务@Transactional注解。 4. 调整feign客户端的超时时间:可以通过配置feign客户端的连接超时时间和读取超时时间,来提高feign远程调用的稳定性。 综上所述,加上@Transactional后feign远程调用超时的问题可能是由于事务的提交时间过长导致的。可以通过调整事务超时时间、使用异步处理、使用独立的事务管理或者调整feign客户端的超时时间来解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Transactional 事务问题引发的fegin调用超时time out](https://blog.csdn.net/weixin_46063176/article/details/117999954)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [大意了,使用@Transactional竟然出现了长事务,导致生产事故!](https://blog.csdn.net/qq_34162294/article/details/121571689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值