异步编程是一种编程模式,通过将任务分解为多个子任务,并在后台或并行线程中执行这些子任务,以提高程序的性能和响应能力。
方法名 | 说明 |
---|---|
void run() | 在线程开启后,此方法将被调用执行,不能直接调用该方法实现多线程 |
void start() | 使此方法开启一个新线程并开始执行,Java虚拟机会自动调用 run方法 |
public class MyThreadDemo extends Thread {
@Override
public void run() {
Long start = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0; i<5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
Long end = System.currentTimeMillis();
System.out.println("线程耗时:"+(end-start)+"毫秒");
}
}
public static void main(String[] args) {
Long start = System.currentTimeMillis();
MyThreadDemo m1 = new MyThreadDemo();
MyThreadDemo m2 = new MyThreadDemo();
m1.start();
m2.start();
Long end = System.currentTimeMillis();
System.out.println("总线程耗时:"+(end-start)+"毫秒");
}
实现结果:
总结: 继承 Thread 类这种实现方式,实现比较简单,但是扩展性差,因为类只能单继承。
new Thread(()->{
执行代码块;
}).start();
Long start = System.currentTimeMillis();
new Thread(() -> {
Long start1 = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Long end1 = System.currentTimeMillis();
System.out.println("线程耗时:"+(end1-start1)+"毫秒");
}).start();
Long end = System.currentTimeMillis();
System.out.println("总线程耗时:"+(end-start)+"毫秒");
实现结果:
注意: JDK8以上版本支持该方法
【Java异常】 Error:java: Compilation failed: internal java compiler error 的解决方案
方法名 | 说明 |
---|---|
Thread(Runnable target) | 传入实现了 Runnable 接口的类,构造一个 Thread 对象 |
Thread(Runnable target, String name) | 传入实现了 Runnable 接口的类,构造一个名称为 name 的 Thread 对象 |
public class AsynchronousThread implements Runnable {
@Override
public void run() {
Long start = System.currentTimeMillis();
try {
Thread.sleep(1000);
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Long end =System.currentTimeMillis();
System.out.println("异步线程耗时:"+(end-start)+"毫秒");
}
}
public static void main(String[] args) {
Long start = System.currentTimeMillis();
AsynchronousThread at= new AsynchronousThread();
Thread thread1= new Thread(at);
Thread thread2 = new Thread(at);
thread1.start();
thread2.start();
Long end =System.currentTimeMillis();
System.out.println("同步线程耗时:"+(end-start)+"毫秒");
}
总结: 实现 Runnable 接口、Callable 接口这两种实现方式,实现比较复杂,但是扩展性比较强。
方法名 | 说明 |
---|---|
V call() | 这是 Callable 接口中要实现的方法,相当于 Runnable 接口中的 run 方法 |
FutureTask(Callable callable) | 使用 Callable 接口实现类实例创建一个 FutureTask,它运行时会调配用 Callable 接口中的 call 方法 |
V get() | FutureTask实例的 get 方法,可以阻塞代码继续往下执行,直到获取到异步线程中的返回结果为止 |
public class CallableThread implements Callable<String> {
@Override
public String call() throws Exception {
Long start = System.currentTimeMillis();
try {
Thread.sleep(1000);
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Long end =System.currentTimeMillis();
System.out.println("异步线程耗时:"+(end-start)+"毫秒");
return "返回异步线程耗时:"+(end-start)+"毫秒";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Long start = System.currentTimeMillis();
CallableThread mc = new CallableThread();
//因为该类实现了String 类型的 Callable 接口
//所以返回值也是 String 类型,所以创建的是 String 类型的 FutureTask 对象
FutureTask<String> ft = new FutureTask<>(mc);
//传入 FutureTask 实例,创建线程对象
Thread t1 = new Thread(ft);
//不能在这个地方使用 FutureTask 的 get 方法获取异步线程的返回值,否则程序将卡死在这里。
//因为 t1 线程还没有执行,所以无法获取到返回值,所以如果执行 get 方法,程序将卡死在这里。
//String s = ft.get();
//开启新线程,异步执行 MyCallable 实例中的 call 方法逻辑
t1.start();
//这里编写一些实现其它业务逻辑代码进行执行
//可以做一些其它比较耗时的任务
//......
Thread.sleep(2000);
//获取异步线程的返回值
String s = ft.get();
System.out.println(s);
Long end =System.currentTimeMillis();
System.out.println("同步线程耗时:"+(end-start)+"毫秒");
}
返回结果:
总结: 如果想要获取到异步线程中的返回值的话,可以采用实现 Callable 接口这种实现方式。
Spring 框架提供的注解,用于将方法标记为异步执行的方法。它的作用是告诉 Spring 框架在调用被注解的方法时,将其放入线程池中异步执行,而不是阻塞等待方法的完成。
在调用被注解的方法时,Spring 会将该方法的执行转移到线程池中的一个线程进行处理。执行完成后,方法的返回值将通过 Future 或 CompletableFuture 进行封装,以便获取方法的返回结果
源码讲解
默认线程池的默认配置如下:
@EnableAsync
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@Configuration
public class AsyncTaskConfig{
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
//设置核心线程数
executor.setCorePoolSize(3);
//最大线程数
executor.setMaxPoolSize(6);
//队列容量
executor.setQueueCapacity(12);
//活跃时间(秒)
executor.setKeepAliveSeconds(60);
//线程名字前缀
executor.setThreadNamePrefix("SyncHistoryInvoice-");
//线程拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
//初始化
executor.initialize();
return executor;
}
}
@Async("taskExecutor")
public void test() throws Exception {
long sleep = random.nextInt(10000);
log.info("开始任务,需耗时:" + sleep + "毫秒");
Thread.sleep(sleep);
log.info("完成任务");
return new AsyncResult<>("test");
}
异步任务类名.test();
四种策略优缺点详解