为什么需要异步任务?有些代码可能影响程序性能,并且不需要实时同步执行,这部分代码就可以放到异步任务中,以减少响应时间。比如在用户操作软件的时候需要记录一些操作日志,频繁写入db的操作会影响用户体验。
实现思路: 首先创建一个AbstractQueue类,用于存放任务队列。然后创建一个AbstractAsynTask类,用于管理AbstractQueue队列。
下面是具体实现:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author: jack
* @Description:抽象异步队列
*/
public abstract class AbstractQueue {
private static Logger log = LoggerFactory.getLogger(AbstractQueue.class);
//队列空闲时间 3分钟
private static final int timeout = 3 * 60 * 1000 ;
//当前任务大小
private volatile AtomicInteger size = new AtomicInteger();
//线程启动开关
private boolean isRun = false;
private volatile Queue<Object> queue = new ConcurrentLinkedQueue();
//线程,用于遍历队列
private volatile Thread thread = null;
//最后执行时间
private volatile long lastTime = System.currentTimeMillis();
//队列名称
public String queueName = "抽象队列";
//线程结果汇总
private volatile StringBuilder resultBuilder = new StringBuilder();
//总数
private volatile AtomicInteger total = new AtomicInteger();
//成功数
private volatile AtomicInteger success = new AtomicInteger();
//失败数
private volatile AtomicInteger fail = new AtomicInteger();
public void add(Object dto) {
queue.add(dto);
size.incrementAndGet();
total.incrementAndGet();
}
private void stop() {
log.error("【" + queueName + "】,线程关闭");
isRun = false;
resultBuilder.append("总数:" + total.intValue() + ",成功数:" + success.intValue() + ",失败数:" + fail.intValue());
log.error(resultBuilder.toString());
}
private void start() {
log.error("【" + queueName + "】,线程开启");
isRun = true;
thread.start();
}
public int getSize() {
return size.get();
}
public AbstractQueue(String queueName) {
this.queueName = queueName;
resultBuilder.append("【" + queueName + "】,执行汇总:").append("\r\n");
thread = new Thread(() -> {
while (isRun) {
Object emailDto = null;
try {
if (!queue.isEmpty()) {
lastTime = System.currentTimeMillis();
emailDto = queue.poll();
size.decrementAndGet();
task(emailDto);
success.incrementAndGet();
}
long currentTime = System.currentTimeMillis();
if ((currentTime - lastTime) >= timeout) {
stop();
} else {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
fail.incrementAndGet();
}
}
});
start();
}
abstract public void task(Object dto);
public boolean isAlive() {
return thread.isAlive() && isRun;
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* @Author: jack
* @Description:抽象异步任务
*/
public abstract class AbstractAsynTask {
//每个队列最大容量
public static final int max_capacity = 500;
//队列列表
public volatile List<AbstractQueue> queueList =new ArrayList<>();
public void add(Object dto){
boolean isAdd = false;
Iterator ite = queueList.iterator();
while(ite.hasNext()){
AbstractQueue queue = (AbstractQueue) ite.next();
if(queue.getSize() >= max_capacity){
continue;
}
if(!queue.isAlive()){
ite.remove();
queueList.add(createNewQueue());
}
queue.add(dto);
isAdd = true;
break;
}
if(!isAdd){
AbstractQueue queue = doCreateNewQueue();
queue.add(dto);
queueList.add(queue);
}
}
public AbstractQueue doCreateNewQueue(){
return createNewQueue();
}
abstract public AbstractQueue createNewQueue();
public int getQueueSize(){
return queueList.size();
}
}
到这已经大功告成了,接下来写个具体实现,测试一下异步任务。
public class SendMsgQueue extends AbstractQueue {
@Override
public void task(Object dto) {
try {
System.out.println("【"+queueName+"】"+"sending content :"+dto);
Thread.sleep(50);
System.out.println("【"+queueName+"】"+"send finish...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public SendMsgQueue(String queueName){
super(queueName);
}
}
public class SendMsgAsynTask extends AbstractAsynTask {
@Override
public AbstractQueue createNewQueue() {
return new SendMsgQueue("消息队列"+getQueueSize());
}
}
然后是测试类
public class test {
public static void main(String[] args) {
SendMsgAsynTask task = new SendMsgAsynTask();
for(int i=0;i<10000;i++){
task.add("hello world");
}
}
}
执行后控制台部分输出如下
[ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列17】,线程开启
【消息队列16】sending content :hello world
【消息队列17】sending content :hello world
2020-04-03 09:39:56
[ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列18】,线程开启
【消息队列18】sending content :hello world
2020-04-03 09:39:56
[ERROR]-[Thread: main]-[com.recovery.www.task.asyn.AbstractQueue.start()]: 【消息队列19】,线程开启
【消息队列19】sending content :hello world
【消息队列0】send finish...
【消息队列1】send finish...
【消息队列2】send finish...
可以看到执行10000个任务总共开启了19个线程。这些任务在线程中串行执行