在Java中,线程池主要用于管理和复用一组预先创建的线程。java.util.concurrent包提供了多种线程池类型,以适应不同的应用场景:
FixedThreadPool:固定大小的线程池。它允许指定线程池中的线程数量,并且会重用这些线程来执行任务。
CachedThreadPool:缓存线程池。它会根据需要创建新线程,但在先前构造的线程可用时会重用它们。如果线程闲置时间超过一定期限,则会被终止并移除。
SingleThreadExecutor:单线程化的线程池。它只会用单一工作线程来执行任务队列中的任务,保证了按顺序执行各个任务。
ScheduledThreadPoolExecutor:定时线程池。它可以调度命令在给定延迟后运行或定期执行。
在实际开发中,可以根据具体需求选择合适的线程池类型,以优化资源利用和提高程序性能。
package XXX.XXX.XXX;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
/**
* @author DreamJ
* @date 2023/7/4
*/
@Component
@Slf4j
public class TestLogsMessageHandler implements ApplicationRunner {
private static final String tmSubPubPort = "6060";
private final List<WebSocketSession> webSocketSessions = new CopyOnWriteArrayList<>();
private final List<WebSocketSession> monitoringWebSocketSessions = new CopyOnWriteArrayList<>();
private final List<WebSocketSession> dataSummaryWebSocketSessions = new CopyOnWriteArrayList<>();
private final List<WebSocketSession> deviceTestMesWebSocketSessions = new CopyOnWriteArrayList<>();
@Resource
private ZmqConfig zmqConfig;
@Resource
private ZmqReceiver zmqReceiver;
public void addWebSocketSession(WebSocketSession session) {
webSocketSessions.add(session);
}
public void removeWebSocketSession(WebSocketSession session) {
webSocketSessions.remove(session);
}
public void addMonitoringWebSocketSession(WebSocketSession session, Map<String, String> params) {
session.getAttributes().putAll(params);
monitoringWebSocketSessions.add(session);
}
public void removeMonitoringWebSocketSession(WebSocketSession session) {
monitoringWebSocketSessions.remove(session);
}
public void addSummaryWebSocketSession(WebSocketSession session, Map<String, String> params) {
session.getAttributes().putAll(params);
dataSummaryWebSocketSessions.add(session);
}
public void removeSummaryWebSocketSession(WebSocketSession session) {
dataSummaryWebSocketSessions.remove(session);
}
public void addDeviceTestMesWebSocketSession(WebSocketSession session, Map<String, String> params) {
session.getAttributes().putAll(params);
deviceTestMesWebSocketSessions.add(session);
}
public void removeDeviceTestMesWebSocketSession(WebSocketSession session) {
deviceTestMesWebSocketSessions.remove(session);
}
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("TestLogs启动监听线程");
List<String> listenerMes = new ArrayList<>();
//监听设备的地址配置
/* listenerMes.add(zmqConfig.getScannerPlcSubPubIp());
listenerMes.add(zmqConfig.getIct1PlcSubPubIp());
listenerMes.add(zmqConfig.getIct1TmSubPubIp());
listenerMes.add(zmqConfig.getIct2PlcSubPubIp());
listenerMes.add(zmqConfig.getIct2TmSubPubIp());
listenerMes.add(zmqConfig.getFct1PlcSubPubIp());
listenerMes.add(zmqConfig.getFct1TmSubPubIp());
listenerMes.add(zmqConfig.getFct2PlcSubPubIp());
listenerMes.add(zmqConfig.getFct2TmSubPubIp());
listenerMes.add(zmqConfig.getFct3PlcSubPubIp());
listenerMes.add(zmqConfig.getFct3TmSubPubIp());
listenerMes.add(zmqConfig.getSortPlcSubPubIp());*/
listenerMes.add(zmqConfig.getScannerPlcSubPubIp());
listenerMes.add(zmqConfig.getIct1PlcSubPubIp());
listenerMes.add(zmqConfig.getIct1TmSubPubIp());
listenerMes.add(zmqConfig.getIsp1PlcSubPubIp());
listenerMes.add(zmqConfig.getIsp1TmSubPubIp());
listenerMes.add(zmqConfig.getIsp2PlcSubPubIp());
listenerMes.add(zmqConfig.getIsp2TmSubPubIp());
listenerMes.add(zmqConfig.getFct1PlcSubPubIp());
listenerMes.add(zmqConfig.getFct1TmSubPubIp());
listenerMes.add(zmqConfig.getSortPlcSubPubIp());
listenerMes.add(zmqConfig.getReceiverAddress());
listenerMes.add(zmqConfig.getReceiver1Address());
LinkedBlockingQueue messageQueue = new LinkedBlockingQueue<>(10000);
//通过在程序启动时创建全局的 ZeroMQ 上下文对象,
//并在每个任务内部使用这个全局的上下文对象来初始化 Socket 对象,
//可以确保每个任务都使用同一个上下文对象,避免线程安全问题
ZContext context = new ZContext();
ExecutorService executorService = ThreadUtil.newExecutor(10,100,100);
for (String ipPort : listenerMes) {
ExecutorService listenerExecutorService = ThreadUtil.newExecutor(10,200,200);
final String finalIpPort = ipPort;
listenerExecutorService.submit(()->{
//根据不同的ip端口和全局ZeroMQ 上下文对象创建SUB连接
ZMQ.Socket socket = context.createSocket(SocketType.SUB);
socket.connect(finalIpPort);
socket.subscribe("");
socket.setReceiveTimeOut(60000);
// 启用 TCP keep-alive 机制
socket.setTCPKeepAlive(1);
while (true) {
//获取ZMQ队列监听的消息
LogObject logObject = new LogObject();
ZMsg message = ZMsg.recvMsg(socket);
if (message != null) {
// 测试
String receiveMes = message.getLast().getString(ZMQ.CHARSET);
// String receiveMes = message.getLast().toString();
// log.info("jk接收数据:{}", receiveMes);
logObject.setIpPort(ipPort);
logObject.setMes(receiveMes);
if (StrUtil.isNotBlank(receiveMes)) {
try {
//将获取到的数据放入队列中
messageQueue.put(logObject);
} catch (InterruptedException e) {
log.error("putMessageQueueThread: " + receiveMes, e);
}
}
}
}
});
}
executorService.submit(() -> takeThread(messageQueue));
}
private void takeThread(LinkedBlockingQueue messageQueue) {
while (true) {
try {
LogObject logObject = (LogObject) messageQueue.take();
//消费队列中的消息
processMessage(logObject);
} catch (InterruptedException e) {
log.error("takeMessageQueueThread: " + messageQueue, e);
}
}
}
private void processMessage(LogObject logObject) {
String receiveMes = logObject.getMes();
try {
JSONObject jsonObject = JSONUtil.parseObj(receiveMes);
TestResult testResult = new TestResult();
BeanUtil.copyProperties(jsonObject, testResult);
//log结构不为空
if(MapUtil.isNotEmpty(testResult.getLog())){
//MonitoringMesListener
ThreadUtil.execAsync(new MonitoringMesListener(monitoringWebSocketSessions, receiveMes));
//DataSummaryMesListener
ThreadUtil.execAsync(new DataSummaryMesListener(dataSummaryWebSocketSessions, receiveMes));
//DeviceTestMesListener
ThreadUtil.execAsync(new DeviceTestMesListener(deviceTestMesWebSocketSessions, receiveMes));
}
//接收到的tm状态与设备状态无关
if(!StrUtil.contains(logObject.getIpPort(),tmSubPubPort)){
//设备状态
ThreadUtil.execAsync(new ProcessMesListener(webSocketSessions,receiveMes));
}
//TODO 对监听到的ZMQ消息做更多的处理....
}catch (Exception e){
log.error("TestLogsMessageHandler异常,异常信息为:{}",e.getMessage());
}
}
}