問題
場景1:一組數據有規律的上報,根據其時間間隔對其分段,判斷其每一段數據的開始與結束
場景2:一個消息一旦開始上報,則會以固定時間間隔上報,消息本身並無開始結束標誌,現需要判斷消息開始與結束
用文字描述不太利索,直接舉例說明:
第1秒:1
第2秒:1
第3秒:1
第4秒:無
第5秒:無
第6秒:1
第7秒:1
第8秒:無
第9秒:1
第10秒:1
第11秒:1
那麼第一段數據就是1到3秒,第二段數據就是6到7秒,第三段數據就是9到11秒。
第1秒:1
第2秒:2
第3秒:3
第4秒:無
第5秒:無
第6秒:4
第7秒:5
第8秒:無
第9秒:6
第10秒:7
第11秒:8
第一段數據爲1/2/3,第二段數據爲4/5,第三段數據爲6/7/8。
最重要的條件,就是時間。
如果在接下的固定時間內能收到下一個數據,那麼代表這段數據並沒有結束上報,反之,這段數據已經上報結束。
在上報的數據本身不能提供更多信息的情況下,只能自行處理。
思路
解決辦法從時間下手,目前有兩種思路:
一,以更高的頻率去輪詢,查詢每兩個相鄰數據的時間間隔,判斷”下一個數據是否”準時“到來,如果未準時,那麼當前的數據就是一段數據的結尾;
二,利用阻塞隊列的特性,判斷下一個數據是否“準時”。
public class EndDemo {
public static void main(String[] args) {
// Determiner determiner = new Determiner("task1");
Blocker blocker = new Blocker("task2");
try {
for (int i = 0; i < 20; i++) {
if (i % 4 == 0) {
TimeUnit.MILLISECONDS.sleep(200);
} else {
TimeUnit.MILLISECONDS.sleep(50);
}
// determiner.check(i);
blocker.check(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 利用粒度更小的時間去輪詢
*/
private static class Determiner {
private long trackTime = 0;
private Thread trackThread;
private volatile boolean startFlag;
private volatile int count;
Determiner(String taskName) {
trackThread = new Thread(() -> {
try {
while (true) {
if (startFlag) {
TimeUnit.MILLISECONDS.sleep(30);
if (System.currentTimeMillis() - trackTime > 100) {
System.out.println("end:" + count);
startFlag = false;
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, taskName);
}
void check(int counter) {
if (!trackThread.isAlive()) {
trackThread.start();
}
count = counter;
if (!startFlag && System.currentTimeMillis() - trackTime > 100) {
System.out.println("start:" + counter);
startFlag = true;
}
trackTime = System.currentTimeMillis();
}
}
/**
* 利用阻塞隊列的特性
*/
private static class Blocker {
private SynchronousQueue<Integer> queue;
private Thread trackThread;
private volatile boolean startFlag;
Blocker(String taskName) {
queue = new SynchronousQueue<>(true);
trackThread = new Thread(() -> {
try {
Integer temp;
int end = 0;
while (true) {
if (startFlag) {
temp = queue.poll(150, TimeUnit.MILLISECONDS);
if (temp == null) {
System.out.println("end:" + end);
startFlag = false;
} else {
end = temp;
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, taskName);
}
void check(int counter) {
if (!trackThread.isAlive()) {
trackThread.start();
}
if (!startFlag && queue.isEmpty()) {
System.out.println("start:"+counter);
startFlag = true;
}
queue.offer(counter);
}
}
}
輸出:
start:0
end:3
start:4
end:7
start:8
end:11
start:12
end:15
start:16
end:19