嘿嘿嘿嘿!虽然简单,还是记录一下,免得太笨了以后又犯同样的错误!
事例介绍:
需求:udp服务端高速接收数据放入环形缓存之中,文件服务和接收端共用同一个缓存文件服务负责取数据并写入磁盘
难点:udp数据接收过快,而来一个数据你就得开启一次io操作进行写磁盘,导致写磁盘速度完全跟不上udp放数据进缓存的速度而数据丢失。
解决方案:文件服务先弄一个udp数据中转线程,再维护一个环形队列用于中转数据,udp服务端的缓存一旦来数据就用文件服务中转线程去取放入中转缓存,一旦这个中转缓存满了就通过构造函数传入参数再去开一个写磁盘的线程,这个线程就把数据全部放入缓存再close() io,而中转线程开完存磁盘的线程之后下一步就new一个新的缓存(不然两个线程操作的是同一个缓存),继续取数据。
//取数据的一个线程,调用存文件的一个线程(数据中转线程)
class SaveTransitThread extends Thread{
private CircleBuffer dataTrains;//数据中转缓存
private CircleBuffer discInteraction;//磁盘交互缓存
private File file;//要存的文件
private String fileName;//名字,前缀,这个是固定不变的
private String flag;
public SaveTransitThread(CircleBuffer dataTrains,CircleBuffer discInteraction,File file,String fileName,String flag){
this.dataTrains=dataTrains;
this.discInteraction= discInteraction;
this.file=file;
this.fileName=fileName;
this.flag=flag;
}
@Override
public void run() {
while (fileSaveTransitThreadlife){
try {
byte[] data = dataTrains.poll(fileTransitThreadPollDataTimeOut, TimeUnit.SECONDS);//设置三十秒超时时间,三十秒后还没有接到数据就返回空
if(data!=null){
boolean offer = discInteraction.offer(data);//放入存文件的缓存中,线程无阻塞的
if(!offer){//一旦存文件的缓存满了之后
fileServiceExecutorService.execute(new SaveDataThread(discInteraction,file,fileName));//放入真正存文件的线程,那边会克隆这个缓存
discInteraction=setStaticQueue();
discInteraction.offer(data);//把刚才没有放进去的数据放进去
}
}else if(data==null&&discInteraction.getCount()>0){//一旦返回空而且存文件的环形缓存中还有数据就把这些数据写入到磁盘中去
fileServiceExecutorService.execute(new SaveDataThread(discInteraction,file,fileName));//放入真正存文件的线程,那边会克隆这个缓存,通过线程池启动
discInteraction=new CircleBuffer(saveFileQuereSize,saveFileQuereDataSize,true);
setStaticQueue();
}else {
Thread.sleep(50);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@PreDestroy
public void destory(){
if(discInteraction!=null&&discInteraction.getCount()>0)
fileServiceExecutorService.execute(new SaveDataThread(discInteraction,file,fileName));
}
public CircleBuffer setStaticQueue() {
CircleBuffer circleBuffer=null;
switch (flag){
case "one":
circleBuffer = new CircleBuffer(saveFileQuereSize, saveFileQuereDataSize, true);
saveFileOneQuere=circleBuffer;
return circleBuffer;
case "two":
circleBuffer = new CircleBuffer(saveFileQuereSize, (saveFileQuereDataSize+500), true);//避免五个缓存同时开io
saveFileTwoQuere=circleBuffer;
return circleBuffer;
case "three":
circleBuffer = new CircleBuffer(saveFileQuereSize, (saveFileQuereDataSize+1000), true);
saveFileThreeQuere=circleBuffer;
return circleBuffer;
case "four":
circleBuffer = new CircleBuffer(saveFileQuereSize, (saveFileQuereDataSize+1500), true);
saveFileFourQuere=circleBuffer;
return circleBuffer;
case "five":
circleBuffer = new CircleBuffer(saveFileQuereSize, (saveFileQuereDataSize+2000), true);
saveFileFiveQuere=circleBuffer;
return circleBuffer;
default:
try {
throw new Exception("文件服务链路不正确");
} catch (Exception e) {
e.printStackTrace();
}
}
return circleBuffer;
}
}