线程池
ExecutorService接口实现类,四种常用线程池:
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
补充:为了合理利用资源,我们通常把定长池的长度设置为当前PC机获取cpu核心数:Runtime.getRuntime().availableProcessors():获取当前CPU核心数;newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
package com.swagger.demo.thread;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class MyThreadPool {
public static void main(String [] args){
int num = Runtime.getRuntime().availableProcessors();
Executor executor = Executors.newFixedThreadPool(num);
for (int i = 0 ; i<num ; i++){
executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("我是一个子线程!!");
}
});
}
}
}
队列
java.ulil.concurrent包提供了阻塞队列的4个变种
- LinkedBlockingQueue在不指定容量时最大容量为Integer.MAX_VALUE它是基于链表的队列,此队列按 FIFO(先进先出)排序元素
PriorityBlockingQueue是一个带优先级的 队列,而不是先进先出队列。元素按优先级顺序被移除,该队列也没有上限(看了一下源码,PriorityBlockingQueue是对 PriorityQueue的再次包装,是基于堆数据结构的,而PriorityQueue是没有容量限制的,与ArrayList一样,所以在优先阻塞 队列上put时是不会受阻的。虽然此队列逻辑上是无界的,但是由于资源被耗尽,所以试图执行添加操作可能会导致 OutOfMemoryError),但是如果队列为空,那么取元素的操作take就会阻塞,所以它的检索操作take是受阻的。另外,往入该队列中的元素要具有比较能力。
DelayQueue(基于PriorityQueue来实现的)是一个存放Delayed 元素的无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于或等于零的值时,则出现期满,poll就以移除这个元素了。此队列不允许使用 null 元素。 下面是延迟接口:
代码如下:
public interface Delayed extends Comparable {
long getDelay(TimeUnit unit);
}
放入DelayQueue的元素还将要实现compareTo方法,DelayQueue使用这个来为元素排序。
应用:
使用的SpringBoot应用环境搭建:
基于AOP的原理实现一个简单的日志处理:
package com.swagger.demo.aop;
import com.swagger.demo.Entity.LogContentEntity;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
@Configuration
@Aspect
@Component
public class AopLogConfig implements Runnable {
@Autowired
private HttpServletRequest request;
private LinkedBlockingQueue<LogContentEntity> logQueue;
public AopLogConfig() {
//Spring启动后,该对象创建时。初始化队列以及线程池。
logQueue = new LinkedBlockingQueue<LogContentEntity>(3000);
int num = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(num);
for (int i = 0 ;i<num ;i++){
executor.execute(this);
}
}
@Before("execution(public * com.swagger.demo.controller..*.*(..))")
public void doBefore(JoinPoint joinPoint) throws Exception{
//日志记录的信息可自行修改
LogContentEntity Log = new LogContentEntity();
String method = request.getMethod();
Log.setHttpMethod(method);
String url = request.getRequestURL().toString();
Log.setUrl(url);
String ip = request.getRemoteAddr();
Log.setIp(ip);
Log.setContent("test Log Content");
//将需要记录的日志对象放到队列中等待线程异步执行。
logQueue.put(Log);
}
@Override
public void run() {
try{
while(true){
//如果队列里没有,则会阻塞;
LogContentEntity take = logQueue.take();
//日志处理逻辑可自行修改;
System.out.println(take.toString());
}
}catch(Exception e){
e.printStackTrace();
}
}
}