Java开启异步的两种方式
Posted kakarotto-chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java开启异步的两种方式相关的知识,希望对你有一定的参考价值。
二、Java开启异步的两种方式
1、注解开启:@Async
1.1、配置异步的线程池
- 必须配置异步线程池,否则异步不会生效。
- @EnableAsync 注解:指定异步线程池。不指定默认使用:SimpleAsyncTaskExecutor线程池
- SimpleAsyncTaskExecutor是一个最简单的线程池,它没有任何的线程相关参数配置,它会为每个任务创建一个新的线程来执行,因此不建议在生产环境中使用。
- 配置线程池见:https://www.cnblogs.com/kakarotto-chen/p/17428432.html
package com.cc.md.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/** IO型的线程池
* @author CC
* @since 2023/5/23 0023
*/
@Configuration
@EnableAsync
public class IoThreadPool
public static final int THREAD_SIZE = 2 * (Runtime.getRuntime().availableProcessors());
public static final int QUEUE_SIZE = 1000;
@Bean(name = "myIoThreadPool")
public ThreadPoolTaskExecutor threadPoolExecutor()
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(THREAD_SIZE);
executor.setMaxPoolSize(THREAD_SIZE);
executor.setQueueCapacity(QUEUE_SIZE);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
executor.setKeepAliveSeconds(60);
executor.setAllowCoreThreadTimeOut(true);
executor.setAwaitTerminationSeconds(300);
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setThreadNamePrefix("myIo-Th-Pool-");
executor.initialize();
return executor;
1.2、异步方法
- 异步方法必须写在另一个类中,否则不生效
- @Async可以打在类上、也可以打在方法上
1 @Async:类上,说明整个类中的方法都是异步。必须写我们自己配置的线程池 —— ("myIoThreadPool")
2 @Async:方法上,说明这个方法是异步。不用写我们自己配置的线程池
- 异步接口+实现类
接口
package com.cc.md.service;
/**
* @author CC
* @since 2023/5/24 0024
*/
public interface IAsyncService
/** 异步方法1
* @since 2023/5/24 0024
* @author CC
**/
void async1();
/** 异步方法2
* @since 2023/5/24 0024
* @author CC
**/
void async2();
实现类
package com.cc.md.service.impl;
import com.cc.md.service.IAsyncService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/** 1 @Async:类上,说明整个类中的方法都是异步。必须写我们自己配置的线程池 —— ("myIoThreadPool")
* 2 @Async:方法上,说明这个方法是异步。不用写我们自己配置的线程池
* @author CC
* @since 2023/5/24 0024
*/
@Service
@Async("myIoThreadPool")
public class AsyncServiceImpl implements IAsyncService
private static final Logger log = LoggerFactory.getLogger(AsyncServiceImpl.class);
//类上写了@Async,这里就可以不写了。
//可以不写 ("myIoThreadPool")。因为在IoThreadPool中开启了异步,说明异步用的就是我们配置的io线程池
//如果类上面打了 @Async ,这里必须写:("myIoThreadPool")
@Override
//@Async
public void async1()
//模仿io流耗时
try
Thread.sleep(5000);
catch (InterruptedException e)
throw new RuntimeException(e);
log.info("打印:", "异步方法1111!");
//@Async在类上面,说明这个方法也是异步方法。如果不打,无法开启异步。
@Override
public void async2()
//模仿io流耗时
try
Thread.sleep(5000);
catch (InterruptedException e)
throw new RuntimeException(e);
log.info("打印:", "异步方法2222!");
1.3、测试
@Resource
private IAsyncService asyncService;
//开启异步1 —— @Async
@Test
public void test03() throws Exception
log.info("打印:", "异步测试的-主方法1");
asyncService.async1();
asyncService.async2();
//不会等待异步方法执行,直接返回前端数据
log.info("打印:", "异步测试的-主方法2");
结果:
2、CompletableFuture的方式
使用:
@Resource(name = "myIoThreadPool")
private ThreadPoolTaskExecutor myIoThreadPool;
//开启异步2 —— CompletableFuture.runAsync()
@Test
public void test04() throws Exception
log.info("打印:", "异步测试的-主方法1");
CompletableFuture.runAsync(() ->
log.info("打印:", "异步方法1!");
//异步执行的代码,也可以是方法,该方法不用单独写到其他类中。
this.async2("异步方法1!-end");
, myIoThreadPool);
//不会等待异步方法执行,直接返回前端数据
log.info("打印:", "异步测试的-主方法2");
//异步需要执行的方法,可以写在同一个类中。
private void async2(String msg)
//模仿io流耗时
try
Thread.sleep(5000);
catch (InterruptedException e)
throw new RuntimeException(e);
log.info("打印:", msg);
结果:
- 后续CompletableFuture的使用见:《Java的CompletableFuture,Java的多线程开发》
35 并行/发 同/异步 非/ 阻塞 进程的两种开启方式, 进程的常用方法及属性
主要内容:
1 名词解释
并行 : 即两件事情或多件事情,在同一时间点同时执行.是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器
并发 : 即两件事情或多件事情在同一时间段交替进行. 是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。
同步 : 所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。
异步 : 所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定, 所以它是不可靠的任务序列.
阻塞 :
非阻塞 :
2 . 开启进程两种方式
1) 第一种
from multiprocessing import Process import os import time def func(i): time.sleep(0.2) print(‘这是子进程%s,pid为%s ,其父进程的pid为%s‘ % (i, os.getpid(), os.getppid())) # os.getpid(), 获得当前进程的pid, # os.getppid(),获得当前进程的父进程的pid if __name__ == ‘__main__‘: for i in range(2): p = Process(target=func, args=(i,)) #实例化一个进程对象 #target:子进程要执行的任务,args:父进程要给子进程传递的参数,必须是元祖形式. p.start() #开启一个进程. time.sleep(0.2) print(‘这是父进程, pid为%s, 其父进程的pid为%s‘ % (os.getpid(), os.getppid()))
2) 继承
from multiprocessing import Process import time import os class Myprocess(Process): def __init__(self): super(Myprocess, self).__init__() def run(self): print(‘在类中创建子进程‘) if __name__ == ‘__main__‘: p = Myprocess() p.start() #是指解释器告诉操作系统, 去帮我开启一个进程, 就绪状态 p.run() # 解释器告诉操作系统,马上帮我执行这个过程. 执行状态
带名字的
from multiprocessing import Process import time import os class Myprocess(Process): def __init__(self, name): self.name = name super(Myprocess, self).__init__(name = name) # 如果不写在执行父类中的__init是name会被覆盖. def run(self): print(‘这是以类的方式开启的子进程, 名字为%s‘ % self.name) if __name__ == ‘__main__‘: p = Myprocess(‘alex‘) p.start() #是指解释器告诉操作系统, 去帮我开启一个进程, 就绪状态. # p.run() # 解释器告诉操作系统立即去开启一个进程, 执行状态.
3 . 进程的常用方法:
1) start 和join
join : 是让主进程等待子进程执行完再执行
from multiprocessing import Process import os import time def func(): for i in range(100): time.sleep(0.1) print(‘这是子进程‘) if __name__ == ‘__main__‘: p = Process(target=func) #子进程要执行的任务 p.start() # p.join() #是让主进程等待子进程执行完, 现象 : 主进程走到这句话, 主进程阻塞住, 等待子进程执行完. for i in range(100): time.sleep(0.1) print(‘这是父进程‘) # 开启一个正常的子进程,父进程会等待子进程结束后,父进程也就是程序才结束 # p.join()# 是让主进程等待子进程执行完。 现象:主进程执行到这句话,主进程阻塞住,等待子进程执行 # 如何把父进程和子进程之间的关系变为同步或者异步? # 父进程执行join,就会变成同步,不执行join,父进程和子进程就是异步的关系 # join必须放在start()后边
2) is_alive 和terminate
def func(): time.sleep(1) if __name__ == ‘__main__‘: p = Process(target=func,) p.start() p.terminate()# 杀死p进程,让解释器告诉操作系统,请杀掉p进程。 print(‘子进程是否还活着?‘, p.is_alive()) time.sleep(0.002) print(‘子进程是否还活着?‘, p.is_alive()) # 返回一个bool值,如果返回True,代表进程还活着,如果返回False,代表子进程死了 # p.is_alive() 判断p进程是否还活着 # p.terminate() 杀死p进程
4 . 进程的常用属性:
1) name 和 pid
from multiprocessing import Process
import time
import os
def func():
print(‘这是子进程, pid为%s‘ % os.getpid())
if __name__ == ‘__main__‘:
p = Process(target=func)
p.start()
p.name = ‘alex‘
print(‘可以查看子进程的pid‘,p.pid)
print(‘可以查看子进程的名字‘, p.name)
print(‘子进程是不是守护进程‘, p.daemon) false
2 ) 守护进程
特点 : 将进程设置为守护进程 , 必须在start之前 daemon = false
守护进程会随着主进程的结束而结束
守护进程不能有子进程.
**守护进程会随着主进程的结束而结束
from multiprocessing import Process
import time
def func():
time.sleep(3.1)
print(‘this is son process‘)
if __name__ == ‘__main__‘:
p = Process(target=func)
p.daemon = True #必须在start之前设置
p.start()
time.sleep(3)
print(‘this is parent process‘)
#守护进程会随着主进程的结束而结束.
**守护进程不能有子进程
from multiprocessing import Process
import time
def func1():
print(‘这里是孙子‘)
def func():
p = Process(target=func1)
p.start()
time.sleep(5)
print(‘这里是儿子哦‘)
if __name__ == ‘__main__‘:
p = Process(target=func)
p.daemon = True # 将p进程设置为守护进程,必须要在start之前设置
p.start()
time.sleep(1)
print(‘这是爸爸‘)
# 守护进程:不允许开启子进程
以上是关于Java开启异步的两种方式的主要内容,如果未能解决你的问题,请参考以下文章