Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
Z
zhmes-agecal
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
耿迪迪
zhmes-agecal
Commits
3214dfa3
Commit
3214dfa3
authored
Sep 24, 2025
by
wanghao
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "1 测试 上电后通信 和 最终完成 定时任务功能"
parent
8f2416a0
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
139 additions
and
233 deletions
+139
-233
DeviceStatusReaderAndTimeSetter.java
...stem/modbus/business/DeviceStatusReaderAndTimeSetter.java
+34
-75
DeviceCommunicationJob.java
...n/java/com/zehong/system/task/DeviceCommunicationJob.java
+91
-139
DeviceTaskScheduler.java
...main/java/com/zehong/system/task/DeviceTaskScheduler.java
+14
-19
No files found.
zhmes-agecal-system/src/main/java/com/zehong/system/modbus/business/DeviceStatusReaderAndTimeSetter.java
View file @
3214dfa3
...
...
@@ -20,8 +20,11 @@ import javax.annotation.Resource;
import
java.lang.reflect.Field
;
import
java.net.Socket
;
import
java.util.List
;
import
java.util.concurrent.*
;
import
java.util.concurrent.atomic.AtomicReference
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.ExecutorService
;
import
java.util.concurrent.Executors
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
java.util.function.Consumer
;
import
java.util.function.Predicate
;
...
...
@@ -39,29 +42,9 @@ public class DeviceStatusReaderAndTimeSetter {
public
static
final
int
TARGET_VALUE
=
1
;
public
static
final
int
MAX_RETRIES
=
1
;
// 仅1次重试(减少总耗时)
public
static
final
int
RETRY_DELAY
=
200
;
// 重试间隔200ms(缩短等待)
// 线程池:Spring管理,非静态(避免资源泄漏)
private
final
ExecutorService
deviceExecutor
;
// 构造函数:初始化线程池(核心线程=设备数/10,避免过多)
public
DeviceStatusReaderAndTimeSetter
()
{
this
.
deviceExecutor
=
new
ThreadPoolExecutor
(
4
,
// 核心线程4个(72个设备,4线程,每线程处理18个,效率适中)
8
,
// 最大线程8个(峰值扩容)
60
,
TimeUnit
.
SECONDS
,
new
LinkedBlockingQueue
<>(
30
),
// 队列30个,避免任务堆积
new
ThreadFactory
()
{
private
int
count
=
0
;
@Override
public
Thread
newThread
(
Runnable
r
)
{
Thread
thread
=
new
Thread
(
r
,
"modbus-device-pool-"
+
(
count
++));
thread
.
setDaemon
(
true
);
// 守护线程,不阻塞JVM退出
return
thread
;
}
},
new
ThreadPoolExecutor
.
CallerRunsPolicy
()
// 队列满时调用线程执行(避免任务丢失)
);
}
// 简化线程池配置
private
final
ExecutorService
deviceExecutor
=
Executors
.
newFixedThreadPool
(
4
);
// 工厂(单例)
private
static
final
ModbusFactory
modbusFactory
=
new
ModbusFactory
();
...
...
@@ -234,76 +217,52 @@ public class DeviceStatusReaderAndTimeSetter {
Consumer
<
DeviceStatusReaderDto
>
resultHandler
,
Predicate
<
int
[]>
stopCondition
,
int
portTimeout
)
{
if
(
deviceIds
==
null
||
deviceIds
.
isEmpty
())
{
log
.
warn
(
"设备ID列表为空,不执行监控:IP={}, 端口={}"
,
ip
,
port
);
return
;
}
if
(
deviceIds
==
null
||
deviceIds
.
isEmpty
())
return
;
final
CountDownLatch
latch
=
new
CountDownLatch
(
deviceIds
.
size
());
log
.
info
(
"启动端口{}监控:IP={},设备数={},超时={}s"
,
port
,
ip
,
deviceIds
.
size
(),
portTimeout
);
CountDownLatch
latch
=
new
CountDownLatch
(
deviceIds
.
size
());
AtomicInteger
successCount
=
new
AtomicInteger
(
0
);
for
(
int
deviceId
:
deviceIds
)
{
final
int
devId
=
deviceId
;
deviceExecutor
.
submit
(()
->
{
// 关键:threadMaster声明为普通ModbusMaster,无需包装
final
ModbusMaster
[]
threadMaster
=
{
null
};
ExecutorService
devExecutor
=
null
;
// 临时线程池,避免泄漏
try
{
// 单个设备超时(端口总超时/设备数,确保不超总时间)
int
devTimeout
=
Math
.
max
(
1
,
portTimeout
*
1000
/
deviceIds
.
size
());
// 创建临时线程池(处理单个设备超时)
devExecutor
=
Executors
.
newSingleThreadExecutor
();
Future
<?>
devFuture
=
devExecutor
.
submit
(()
->
{
try
{
// 1. 创建独立连接(直接赋值,无需get())
threadMaster
[
0
]
=
createModbusMaster
(
ip
,
port
);
// 2. 读取数据(直接传threadMaster,无需get())
int
[]
result
=
readWithConditionalRetry
(
threadMaster
[
0
],
ip
,
port
,
devId
,
stopCondition
);
// 3. 回调结果
if
(
resultHandler
!=
null
)
{
resultHandler
.
accept
(
new
DeviceStatusReaderDto
(
ip
,
port
,
devId
,
result
));
}
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"设备"
+
devId
+
"执行异常"
,
e
);
}
});
// 单个设备超时等待
devFuture
.
get
(
devTimeout
,
TimeUnit
.
MILLISECONDS
);
}
catch
(
TimeoutException
e
)
{
String
errMsg
=
"设备"
+
devId
+
"超时:IP="
+
ip
+
", 端口="
+
port
;
log
.
error
(
errMsg
,
e
);
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
errMsg
);
// 简化设备通信逻辑
executeSingleDevice
(
ip
,
port
,
deviceId
,
resultHandler
,
stopCondition
);
successCount
.
incrementAndGet
();
}
catch
(
Exception
e
)
{
String
errMsg
=
"设备"
+
devId
+
"执行异常:IP="
+
ip
+
", 端口="
+
port
;
log
.
error
(
errMsg
,
e
);
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
+
",deviceId:"
+
devId
,
errMsg
+
":"
+
e
.
getMessage
());
log
.
error
(
"设备通信失败: ip={}, port={}, deviceId={}"
,
ip
,
port
,
deviceId
,
e
);
}
finally
{
// 1. 销毁Modbus连接(直接传threadMaster,无需get())
destroyModbusMaster
(
threadMaster
[
0
],
devId
);
// 2. 关闭临时线程池(避免资源泄漏)
if
(
devExecutor
!=
null
&&
!
devExecutor
.
isShutdown
())
{
devExecutor
.
shutdownNow
();
}
// 3. 计数减1
latch
.
countDown
();
log
.
debug
(
"设备{}完成:IP={}, 端口={},剩余任务={}"
,
devId
,
ip
,
port
,
latch
.
getCount
());
}
});
}
// 端口总超时等待(确保不阻塞上层Job)
try
{
// 等待所有设备完成或超时
if
(!
latch
.
await
(
portTimeout
,
TimeUnit
.
SECONDS
))
{
String
errMsg
=
"端口"
+
port
+
"部分设备超时:IP="
+
ip
+
",未完成="
+
latch
.
getCount
();
log
.
warn
(
errMsg
);
recordAlarm
(
"03"
,
"ip:"
+
ip
+
",port:"
+
port
,
errMsg
);
log
.
warn
(
"端口通信超时: ip={}, port={}, 完成数={}/{}"
,
ip
,
port
,
successCount
.
get
(),
deviceIds
.
size
());
}
}
catch
(
InterruptedException
e
)
{
log
.
error
(
"端口{}监控被中断:IP={}"
,
port
,
ip
,
e
);
Thread
.
currentThread
().
interrupt
();
}
}
private
void
executeSingleDevice
(
String
ip
,
int
port
,
int
deviceId
,
Consumer
<
DeviceStatusReaderDto
>
resultHandler
,
Predicate
<
int
[]>
stopCondition
)
{
ModbusMaster
master
=
null
;
try
{
master
=
createModbusMaster
(
ip
,
port
);
int
[]
result
=
readWithConditionalRetry
(
master
,
ip
,
port
,
deviceId
,
stopCondition
);
if
(
resultHandler
!=
null
)
{
resultHandler
.
accept
(
new
DeviceStatusReaderDto
(
ip
,
port
,
deviceId
,
result
));
}
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"设备通信异常"
,
e
);
}
finally
{
destroyModbusMaster
(
master
,
deviceId
);
}
}
/**
* 统一告警记录(抽离避免重复代码)
*/
...
...
zhmes-agecal-system/src/main/java/com/zehong/system/task/DeviceCommunicationJob.java
View file @
3214dfa3
This diff is collapsed.
Click to expand it.
zhmes-agecal-system/src/main/java/com/zehong/system/task/DeviceTaskScheduler.java
View file @
3214dfa3
...
...
@@ -81,39 +81,34 @@ public class DeviceTaskScheduler {
private
void
createHourlyCommunicationJob
(
Long
fStoreyId
)
throws
SchedulerException
{
String
jobId
=
"COMM_"
+
fStoreyId
;
JobKey
jobKey
=
new
JobKey
(
jobId
,
JOB_GROUP
);
TriggerKey
triggerKey
=
new
TriggerKey
(
jobId
+
"_TRIGGER"
,
TRIGGER_GROUP
);
// 1. 构建JobDetail(仅元数据,禁止并发执行通过注解控制)
JobDetail
job
=
JobBuilder
.
newJob
(
DeviceCommunicationJob
.
class
)
.
withIdentity
(
jobKey
)
.
withDescription
(
"设备"
+
fStoreyId
+
"每5分钟Modbus通信任务"
)
.
usingJobData
(
"fStoreyId"
,
fStoreyId
.
toString
())
// 传递参数(String避免类型问题)
.
storeDurably
(
false
)
// 触发器删除后Job自动失效
.
requestRecovery
(
true
)
// 服务重启后恢复未完成任务
.
usingJobData
(
"fStoreyId"
,
fStoreyId
.
toString
())
.
storeDurably
(
false
)
.
build
();
//
2. 构建CronTrigger(移除withMisfireThreshold,兼容低版本)
//
使用更宽松的misfire策略
CronTrigger
trigger
=
TriggerBuilder
.
newTrigger
()
.
withIdentity
(
triggerKey
)
.
withIdentity
(
jobId
+
"_TRIGGER"
,
TRIGGER_GROUP
)
.
forJob
(
jobKey
)
.
withDescription
(
"设备"
+
fStoreyId
+
"通信任务触发器(每5分钟)"
)
.
withSchedule
(
CronScheduleBuilder
.
cronSchedule
(
CRON_EXPRESSION
)
// Misfire策略:错过触发后立即执行,再按原计划(低版本支持)
.
withMisfireHandlingInstructionFireAndProceed
())
.
withMisfireHandlingInstructionDoNothing
())
// 错过就忽略
.
startNow
()
.
endAt
(
Date
.
from
(
Instant
.
now
().
plus
(
TASK_VALID_DAYS
,
ChronoUnit
.
DAYS
)))
.
build
();
//
3. 原子操作:创建/更新(优先更新,避免删除重建)
//
清理旧任务时更温和
if
(
scheduler
.
checkExists
(
jobKey
))
{
Date
nextFireTime
=
scheduler
.
rescheduleJob
(
triggerKey
,
trigger
);
log
.
info
(
"通信任务[{}]更新触发器成功,下次执行时间:{}"
,
jobId
,
nextFireTime
);
}
else
{
Date
nextFireTime
=
scheduler
.
scheduleJob
(
job
,
trigger
);
log
.
info
(
"通信任务[{}]创建成功,下次执行时间:{}"
,
jobId
,
nextFireTim
e
);
scheduler
.
deleteJob
(
jobKey
);
try
{
Thread
.
sleep
(
100
);
// 短暂等待确保清理完成
}
catch
(
InterruptedException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
scheduler
.
scheduleJob
(
job
,
trigger
);
}
/**
* 2. 创建15分钟后执行的最终任务(保持原逻辑,优化超时)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment