1,初始化线程池
@Component
public class InitListener {
@PostConstruct
public void init() {
// 初始化工作线程池和内存队列
RequestProcessorThreadPool.init();
}
}
2.请求处理线程池
package org.concu.lis;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 请求处理线程池:单例
*/
public class RequestProcessorThreadPool {
// 在实际项目中,你设置线程池大小是多少,每个线程监控的那个内存队列的大小是多少
// 都可以做到一个外部的配置文件中
// 我们这了就给简化了,直接写死了,好吧
/**
* 线程池
*/
private ExecutorService threadPool = Executors.newFixedThreadPool(10);
public RequestProcessorThreadPool() {
RequestQueue requestQueue = RequestQueue.getInstance();
for (int i = 0; i < 10; i++) {
//数组阻塞队列
ArrayBlockingQueue<Request> queue = new ArrayBlockingQueue<Request>(100);//队列容量 100
requestQueue.addQueue(queue);
threadPool.submit(new RequestProcessorThread(queue));
}
}
/**
* 单例有很多种方式去实现:我采取绝对线程安全的一种方式
* 静态内部类的方式,去初始化单
*/
private static class Singleton {
private static RequestProcessorThreadPool instance;
static {
instance = new RequestProcessorThreadPool();
}
public static RequestProcessorThreadPool getInstance() {
return instance;
}
}
/**
* jvm的机制去保证多线程并发安全
* <p>
* 内部类的初始化,一定只会发生一次,不管多少个线程并发去初始化
*
* @return
*/
public static RequestProcessorThreadPool getInstance() {
return Singleton.getInstance();
}
/**
* 初始化的便捷方法
*/
public static void init() {
getInstance();
}
}
3.执行请求的工作线程
package org.concu.lis;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
/**
* 执行请求的工作线程
*/
public class RequestProcessorThread implements Callable<Boolean> {
/**
* 自己监控的内存队列
*/
private ArrayBlockingQueue<Request> queue;
public RequestProcessorThread(ArrayBlockingQueue<Request> queue) {
this.queue = queue;
}
@Override
public Boolean call() throws Exception {
try {
while(true) {
// ArrayBlockingQueue
// Blocking就是说明,如果队列满了,或者是空的,那么都会在执行操作的时候,阻塞住
Request request = queue.take();
// 执行这个request操作
request.process();
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
4.请求内存队列
package org.concu.lis;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
/**
* 请求内存队列
*/
public class RequestQueue {
/**
* 内存队列
*/
private List<ArrayBlockingQueue<Request>> queues = new ArrayList<ArrayBlockingQueue<Request>>();
/**
* 单例有很多种方式去实现:我采取绝对线程安全的一种方式
* 静态内部类的方式,去初始化单例
*/
private static class Singleton {
private static RequestQueue instance;
static {
instance = new RequestQueue();
}
public static RequestQueue getInstance() {
return instance;
}
}
/**
* jvm的机制去保证多线程并发安全
*
* 内部类的初始化,一定只会发生一次,不管多少个线程并发去初始化
*/
public static RequestQueue getInstance() {
return Singleton.getInstance();
}
/**
* 添加一个内存队列
* @param queue
*/
public void addQueue(ArrayBlockingQueue<Request> queue) {
this.queues.add(queue);
}
/**
* 获取内存队列的数量
* @return
*/
public int queueSize() {
return queues.size();
}
/**
* 获取内存队列
* @param index
* @return
*/
public ArrayBlockingQueue<Request> getQueue(int index) {
return queues.get(index);
}
}
5.执行请求的工作线程
package org.concu.lis;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
/**
* 执行请求的工作线程
*/
public class RequestProcessorThread implements Callable<Boolean> {
/**
* 自己监控的内存队列
*/
private ArrayBlockingQueue<Request> queue;
public RequestProcessorThread(ArrayBlockingQueue<Request> queue) {
this.queue = queue;
}
@Override
public Boolean call() throws Exception {
try {
while(true) {
// ArrayBlockingQueue
// Blocking就是说明,如果队列满了,或者是空的,那么都会在执行操作的时候,阻塞住
Request request = queue.take();
// 执行这个request操作
request.process();
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
6.请求异步执行的service
/**
* 请求异步执行的service
*/
public interface RequestAsyncProcessService {
void process(Request request);
}
package org.concu.lis;
import org.springframework.stereotype.Service;
import java.util.concurrent.ArrayBlockingQueue;
/**
* 请求异步处理的service实现
*/
@Service("requestAsyncProcessService")
public class RequestAsyncProcessServiceImpl implements RequestAsyncProcessService {
@Override
public void process(Request request) {
try {
// 做请求的路由,根据每个请求的商品id,路由到对应的内存队列中去
ArrayBlockingQueue<Request> queue = getRoutingQueue(request.getInfo().getId());
// 将请求放入对应的队列中,完成路由操作
queue.put(request);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 获取路由到的内存队列
* @param id 数据ID
* @return 内存队列
*/
private ArrayBlockingQueue<Request> getRoutingQueue(Long id) {
RequestQueue requestQueue = RequestQueue.getInstance();
// 先获取productId的hash值
String key = String.valueOf(id);
int h;
int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
// 对hash值取模,将hash值路由到指定的内存队列中,比如内存队列大小8
// 用内存队列的数量对hash值取模之后,结果一定是在0~7之间
// 所以任何一个商品id都会被固定路由到同样的一个内存队列中去的
int index = (requestQueue.queueSize() - 1) & hash;
System.out.println("===========日志===========: 路由内存队列,id=" + id + ", 队列索引=" + index);
return requestQueue.getQueue(index);
}
}
7.请求接口
/**
* 请求接口
*/
public interface Request {
ModelInfo getInfo();
void process();
}
@AllArgsConstructor
@Data
public class ModelInfo {
private Long id;
private String msg;
}
/**
* 更新数据的请求
*/
public class UpdateDataRequest implements Request {
private ModelInfo info;
public UpdateDataRequest(ModelInfo info){
this.info = info;
}
@Override
public ModelInfo getInfo() {
return this.info;
}
@Override
public void process() {
try {
TimeUnit.MILLISECONDS.sleep(3000);//模拟数据处理
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("接收到请求["+info.getId()+"]~["+info.getMsg()+"]:更新数据,刷新缓存等操作 按照顺序依次执行 SUCCESS !");
}
}
8.测试
@Controller
public class TestController {
@Resource
private RequestAsyncProcessService service;
private static int countNumber = 1;
/**
* 更新数据
*/
@RequestMapping("/update")
@ResponseBody
public String updateInfo(Long id) {
int number = countNumber++;
System.out.println("===========日志===========: 接收到更新的请求,数据id=" + id + " count:"+number);
String response = "操作失败";
try {
ModelInfo info = new ModelInfo(id,String.valueOf(number));
Request request = new UpdateDataRequest(info);
service.process(request);
response = "操作成功";
} catch (Exception e) {
e.printStackTrace();
response = "操作失败";
}
return response;
}
}
————————————————
版权声明:本文为CSDN博主「hold_on_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:Spring Boot 使用Listener 初始化【线程池+内存队列】 线程池+内存队列初始_心要是孤单了,到了那里都是流浪~~~-CSDN博客