zoukankan      html  css  js  c++  java
  • Java Design Demo -简单的队列-异步多任务队列(java android)

    简单的单线程队列 -- 工作的时候遇到劣质打印机。给打印机发消息,打印机就会打印,如果在打印机还在打印的时候,就

    再发消息打印,就会出现消息丢失。所以需要给上一个任务一些处理的间隔时间.

    单线程的消息队列示例

    1. package demo1;  
    2.   
    3. import java.util.LinkedList;  
    4.   
    5. public class Main {  
    6.   
    7.     /** 
    8.      * @param args 
    9.      */  
    10.   
    11.     private static Thread thread;  
    12.     private static LinkedList<Runnable> list = new LinkedList<Runnable>();  
    13.   
    14.     static int test = 0;  
    15.   
    16.     public static void main(String[] args) {  
    17.         // TODO Auto-generated method stub  
    18.         final long time = System.currentTimeMillis();  
    19.         for (int i = 0; i < 20; i++) {  
    20.   
    21.             tastEvent(new Runnable() {  
    22.                 public void run() {  
    23.   
    24.   
    25.                         try {  
    26.                             Thread.sleep(500);  
    27.                         } catch (InterruptedException e) {  
    28.                             // TODO Auto-generated catch block  
    29.                             e.printStackTrace();  
    30.                         }  
    31.   
    32.                         System.out  
    33.                                 .println("第"  
    34.                                         + (++test)  
    35.                                         + ("个任务  耗时:" + (System  
    36.                                                 .currentTimeMillis() - time)));  
    37.                     }  
    38.   
    39.             });  
    40.         }  
    41.     }  
    42.   
    43.     public static void tastEvent(Runnable r) {  
    44.         synchronized (list) {  
    45.             list.add(r);  
    46.         }  
    47.             if (thread == null) {  
    48.                 thread = new Thread(run);  
    49.                 thread.start();  
    50.             }  
    51.   
    52.   
    53.     }  
    54.   
    55.     static Runnable run = new Runnable() {  
    56.   
    57.         @Override  
    58.         public void run() {  
    59.             // TODO Auto-generated method stub  
    60.             synchronized (list) {  
    61.   
    62.                 while (!list.isEmpty()) {  
    63.                     // new Thread(list.poll()).start();  
    64.                     list.poll().run();  
    65.                 }  
    66.                 thread = null;  
    67.             }  
    68.         }  
    69.     };  
    70.   
    71. }  


    工作的时候遇到非常大的并发的情况,比如机器1秒只支持1000的并发,但是1秒接收了4000的并发。服务器就会崩掉。

    最好将并发放到队列中,按1000的并发吞吐量来处理,这就是异步队列应用。

    一个工程交给一个人做,需要花费3个月,交给2个人做,需要2个人做需要2个月,需要3个人做需要1个月半.....100.人.....1000人,几年也完不成。

    带上以上道理看待以下的代码

    观察以下代码(复制到android工程下运行):最后耗时约1600毫秒 而使用android的AsyncTask类来改写这段代码只需要耗时约200 

    1. final long  timer=System.currentTimeMillis();  
    2. count=0;  
    3. final Handler h=new Handler();  
    4. for(int k=0;k<100;k++){  
    5. new Thread(){  
    6.     @Override  
    7.     public void run() {  
    8.         // TODO Auto-generated method stub  
    9.         try {  
    10.             Thread.sleep(10);  
    11.         } catch (InterruptedException e) {  
    12.             // TODO Auto-generated catch block  
    13.             e.printStackTrace();  
    14.         }  
    15.         h.post(new Runnable() {  
    16.             @Override  
    17.             public void run() {  
    18.                 Toast.makeText(getApplicationContext()," 耗时"+ (System.currentTimeMillis() - timer), 1).show();  
    19.                 System.err.println("编号"+(count++)+"线程消耗了"+(System.currentTimeMillis()-timer));  
    20.             }  
    21.         });  
    22.     }  
    23. }.start();  



    可见增加多线程不提高性能,反而因为系统在不同的线程之间切换降低效率。因此我们需要让线程有序执行任务

    以下是异步多线程处理队列的demo

    1. package demo2;  
    2.   
    3. import demo2.Task.OnFinishListen;  
    4.   
    5. public class Main {  
    6.   
    7.     /** 
    8.      * @param args 
    9.      */  
    10.     public static void main(String[] args) {  
    11.         // TODO Auto-generated method stub  
    12.           
    13.         Task.setThreadMaxNum(3);  
    14.         for (int i = 0; i < 15; i++) {  
    15.             new Task() {  
    16.   
    17.                 @Override  
    18.                 public Object obtainData(Task task, Object parameter)  
    19.                         throws Exception {  
    20.                     // TODO Auto-generated method stub  
    21.                     Thread.sleep(500);  
    22.                     return task.taskID;  
    23.                 }  
    24.   
    25.             }  
    26.             .setOnFinishListen(new OnFinishListen() {  
    27.   
    28.                 @Override  
    29.                 public void onFinish(Task task, Object data) {  
    30.                     // TODO Auto-generated method stub  
    31.                     System.err.println("任务编号"+task.taskID+"任务完成");  
    32.                 }  
    33.             })  
    34.             .setTaskID(i)  
    35.             .start();  
    36.         }  
    37.     }  
    38.   
    39. }  



    1. package demo2;  
    2.   
    3. import java.util.HashMap;  
    4.   
    5. import java.util.Map;  
    6. import java.util.Observable;  
    7. import java.util.Observer;  
    8.   
    9. public abstract class Task<P,R> implements Runnable, Observer,TaskAction<P,R>{  
    10.   
    11.       
    12.   
    13.       
    14.     //设置最大任务数  
    15.     public static void setThreadMaxNum(int num) {  
    16.         TaskQueue.ThreadMaxNum = num<1?1:num>100?100:num;  
    17.     }  
    18.   
    19.       
    20.       
    21.     public static enum TaskPriority {  
    22.         max, min;  
    23.     }  
    24.   
    25.     /** 单例 可以提高性能 */  
    26.     protected final static Exception withoutException = new Exception(  
    27.             "The state is without");  
    28.   
    29.     // 名字映射  
    30.     private static HashMap<String, Task> nameTasks;  
    31.   
    32.     public static HashMap<String, Task> getNameTask() {  
    33.         if (nameTasks == null) {  
    34.             nameTasks = new HashMap<String, Task>();  
    35.         }  
    36.         return nameTasks;  
    37.   
    38.     }  
    39.   
    40.     public Task<P,R> setSingletonName(String singletonName) {  
    41.         this.singletonName = singletonName;  
    42.         return this;  
    43.     }  
    44.   
    45.     public String getSingletonName() {  
    46.         return singletonName;  
    47.     }  
    48.   
    49.     public interface OnStartListen {  
    50.         void onStart(Task t);  
    51.     }  
    52.   
    53.     public interface OnProgressListen {  
    54.         void onProgress(Task task, int progress, Object data);  
    55.     }  
    56.   
    57.     public static interface OnFinishListen<P,R> {  
    58.         void onFinish(Task<P,R> task, R data);  
    59.     }  
    60.   
    61.     public interface OnSystemStartListen {  
    62.         void onSystemStart(Task task);  
    63.     }  
    64.   
    65.     public interface OnSystemFinishListen {  
    66.         void OnSystemFinish(Task t, Object data);  
    67.     }  
    68.   
    69.       
    70.   
    71.     /** 请求参数 */  
    72.     protected P parameter;  
    73.     /** 任务开始监听 */  
    74.     protected OnStartListen onStartListen;  
    75.     /** 任务进度监听 */  
    76.     protected OnProgressListen onProgressListen;  
    77.     /** 任务完成监听 */  
    78.     protected OnFinishListen<P,R> onFinishListen;  
    79.     /** 任务在队列中完成 监听 */  
    80.     protected OnSystemStartListen onSystemStartListen;  
    81.     /** 任务在队列中开始 监听 */  
    82.     protected OnSystemFinishListen onSystemFinishListen;  
    83.     /** 用于任务完成后发送消息 */  
    84.     /** 结果 */  
    85.     protected R result;  
    86.     /** 任务编号标示 */  
    87.     protected int taskID = -1;  
    88.     /** 任务名字标示 */  
    89.     /** 设置此任务名是否为单例,单例模式下,如果相同名字的任务未执行完,则无法添加新任务 */  
    90.     protected String singletonName;  
    91.   
    92.     /** 保存一个对象 */  
    93.     protected Object tag;  
    94.     /** 获得当前自身线程的引用 在threadRun方法 */  
    95.     protected Thread thread;  
    96.     /** 重连次数 */  
    97.     protected int tryAgainCount = 1;  
    98.     /** 重连间隔 */  
    99.     protected int tryAgainTime = 1000;  
    100.   
    101.   
    102.   
    103.     /** 默认优先级低 */  
    104.     protected TaskPriority priority = TaskPriority.min;  
    105.   
    106.   
    107.     protected HashMap<String,Object> dataMap;  
    108.       
    109.   
    110.     protected Task() {  
    111.     }  
    112.   
    113.   
    114.   
    115.     // 任务状态  
    116.     public static enum TaskStatus {  
    117.         // 未处理 出错 完成 执行中 排除  
    118.         untreated, wait,error, finsh, running, without;  
    119.     }  
    120.   
    121.     /** 状态 */  
    122.     TaskStatus status = TaskStatus.untreated;  
    123.   
    124.     public void setWithout() {  
    125.         this.status = TaskStatus.without;  
    126.     }  
    127.   
    128.     public void remove() {  
    129.         this.status = TaskStatus.without;  
    130.     }  
    131.   
    132.     public TaskPriority getPriority() {  
    133.         return priority;  
    134.     }  
    135.   
    136.     public void setPriority(TaskPriority priority) {  
    137.         this.priority = priority;  
    138.     }  
    139.   
    140.   
    141.       
    142.     /** 启动线程 */  
    143.     public void start() {  
    144.         if (this.priority == null)  
    145.             this.priority = TaskPriority.min;  
    146.           
    147.         synchronized (TaskQueue.tasks_wait) {  
    148.             if (getSingletonName() != null  
    149.                     && Task.getNameTask().get(this.getSingletonName()) != null) {  
    150.                 this.setWithout();  
    151.             } else {  
    152.                 Task.getNameTask().put(this.getSingletonName(), this);  
    153.   
    154.             }  
    155.   
    156.             switch (priority) {  
    157.             case min:  
    158.                 TaskQueue.tasks_wait.remove(this);  
    159.                 TaskQueue.tasks_wait.add(this);  
    160.                 break;  
    161.             case max:  
    162.                 TaskQueue.tasks_wait.remove(this);  
    163.                 TaskQueue.tasks_wait.addFirst(this);  
    164.                 break;  
    165.             default:  
    166.                 break;  
    167.             }  
    168.             // 启动此服务  
    169.             TaskQueue.serivesRun();  
    170.         }  
    171.           
    172.     }  
    173.   
    174.     /** 启动线程 */  
    175.     public void start(TaskPriority priority) {  
    176.           
    177.           
    178.         this.priority = priority;  
    179.         status=TaskStatus.wait;  
    180.         start();  
    181.     }  
    182.   
    183.   
    184.     /** 启动线程 */  
    185.     final void threadRun() {  
    186.         thread = new Thread(this);  
    187.         thread.start();  
    188.     }  
    189.   
    190.     // 中断Execute方法  
    191.     public  void shutDownExecute(){};  
    192.   
    193.     public  R cacheData(P parameter){  
    194.         return result;};  
    195.   
    196.     // 禁止被重写  
    197.     public final Object Execute() throws Exception {  
    198.         // TODO Auto-generated method stub  
    199.         if (onStartListen != null)  
    200.             onStartListen.onStart(this);  
    201.   
    202.         // 队列中回调  
    203.         if (onSystemStartListen != null)  
    204.             onSystemStartListen.onSystemStart(this);  
    205.         // 状态从未处理改变为处理中  
    206.         status = TaskStatus.running;  
    207.   
    208.         // 获取最后一次是否错误  
    209.         Exception exception = null;  
    210.         // 是否有缓存数据如果没有  
    211.         if ((result = cacheData(parameter)) == null) {  
    212.   
    213.             // 失败重联次数  
    214.             for (int i = 0; i < tryAgainCount; i++) {  
    215.                 try {  
    216.                     // 如果状态改变为排除则跳出失败重联  
    217.                     if (status == TaskStatus.without) {  
    218.                         break;  
    219.                     }  
    220.                     exception = null;  
    221.                     result = obtainData(this, parameter);  
    222.                     System.out.println("result=" + result);  
    223.                     break;  
    224.                 } catch (Exception e) {  
    225.                     // TODO Auto-generated catch block  
    226.                     if ((exception = e) == withoutException) {  
    227.                         break;  
    228.                     }  
    229.                     e.printStackTrace();  
    230.                     try {  
    231.                         Thread.sleep(tryAgainTime);  
    232.                     } catch (Exception e1) {  
    233.                         // TODO Auto-generated catch block  
    234.                         e1.printStackTrace();  
    235.                     }  
    236.                 }  
    237.             }  
    238.         }  
    239.         // 如果最后一次仍然失败则抛出  
    240.         if (exception != null) {  
    241.             throw exception;  
    242.         }  
    243.   
    244.   
    245.         // 如果状态改变为处理完但不通知  
    246.         if (status != TaskStatus.without) {  
    247.   
    248.             if (onFinishListen != null) {  
    249.                 //完成监听并将结果加入到主线程  
    250.                 onFinishListen.onFinish(this, result);  
    251.             }  
    252.             ;  
    253.   
    254.   
    255.         }  
    256.         if (onSystemFinishListen != null) {  
    257.             onSystemFinishListen.OnSystemFinish(this, result);  
    258.         }  
    259.         status = TaskStatus.finsh;  
    260.         return result;  
    261.     }  
    262.   
    263.     public abstract  R obtainData(Task<P,R> task, P parameter)throws Exception;  
    264.   
    265.     @Override  
    266.     public void update(Observable observable, Object data) {  
    267.         // 移除观察  
    268.         observable.deleteObserver(this);  
    269.         // 中断 停止关闭连接  
    270.         this.shutDownExecute();  
    271.         this.setWithout();  
    272.         if (this.thread != null) {  
    273.             this.thread.interrupt();  
    274.         }  
    275.         // 错误尝试次数为0  
    276.         this.tryAgainCount = 0;  
    277.     };  
    278.   
    279.     @Override  
    280.     public void run() {  
    281.   
    282.         try {  
    283.             Execute();  
    284.         } catch (Exception e) {  
    285.             e.printStackTrace();  
    286.             status = TaskStatus.error;  
    287.   
    288.   
    289.               
    290.             // 如果状态改变为处理完但不通知  
    291.             if (status != TaskStatus.without) {  
    292.                   
    293.                 if (onFinishListen != null) {  
    294.                     //将结果加入到主线程  
    295.                     onFinishListen.onFinish(this, result);  
    296.                 }  
    297.   
    298.             }  
    299.             if (onSystemFinishListen != null) {  
    300.                 onSystemFinishListen.OnSystemFinish(this, e);  
    301.             }  
    302.         }  
    303.   
    304.         //递归 避免新开线程   唤醒等待中的任务   
    305.         TaskQueue.getRunnable().notifyWaitingTask();  
    306.           
    307.     }  
    308.   
    309.   
    310.   
    311.     public Object getTag() {  
    312.         return tag;  
    313.     }  
    314.   
    315.     public Task setTag(Object tag) {  
    316.         this.tag = tag;  
    317.         return this;  
    318.     }  
    319.   
    320.     public Thread getThread() {  
    321.         return thread;  
    322.     }  
    323.   
    324.     public TaskStatus getStatus() {  
    325.         return status;  
    326.     }  
    327.   
    328.     public Object getParameter() {  
    329.         return parameter;  
    330.     }  
    331.   
    332.     public Task setParameter(P parameter) {  
    333.         this.parameter = parameter;  
    334.         return this;  
    335.     }  
    336.   
    337.     public OnStartListen getOnStartListen() {  
    338.         return onStartListen;  
    339.     }  
    340.   
    341.     public Task setOnStartListen(OnStartListen onStartListen) {  
    342.         this.onStartListen = onStartListen;  
    343.         return this;  
    344.     }  
    345.   
    346.     public OnProgressListen getOnProgressListen() {  
    347.         return onProgressListen;  
    348.     }  
    349.   
    350.     public Task setOnProgressListen(OnProgressListen onProgressListen) {  
    351.         this.onProgressListen = onProgressListen;  
    352.         return this;  
    353.     }  
    354.   
    355.     public OnFinishListen getOnFinishListen() {  
    356.         return onFinishListen;  
    357.     }  
    358.   
    359.     public Task setOnFinishListen(OnFinishListen onFinishListen) {  
    360.         this.onFinishListen = onFinishListen;  
    361.         return this;  
    362.     }  
    363.   
    364.     public OnSystemStartListen getOnSystemStartListen() {  
    365.         return onSystemStartListen;  
    366.     }  
    367.   
    368.     public OnSystemFinishListen getOnSystemFinishListen() {  
    369.         return onSystemFinishListen;  
    370.     }  
    371.   
    372.     public void setOnSystemFinishListen(  
    373.             OnSystemFinishListen onSystemFinishListen) {  
    374.         this.onSystemFinishListen = onSystemFinishListen;  
    375.     }  
    376.   
    377.   
    378.     public int getTaskID() {  
    379.         return taskID;  
    380.     }  
    381.   
    382.     public Task setTaskID(int taskID) {  
    383.         this.taskID = taskID;  
    384.         return this;  
    385.     }  
    386.   
    387.     public Object getResult() {  
    388.         return result;  
    389.     }  
    390.   
    391.     public int getTryAgainCount() {  
    392.         return tryAgainCount;  
    393.     }  
    394.   
    395.     public Task setTryAgainCount(int tryAgainCount) {  
    396.         this.tryAgainCount = tryAgainCount;  
    397.         return this;  
    398.     }  
    399.   
    400.     public int getTryAgainTime() {  
    401.         return tryAgainTime;  
    402.     }  
    403.   
    404.     private Task setTryAgainTime(int tryAgainTime) {  
    405.         this.tryAgainTime = tryAgainTime;  
    406.         return this;  
    407.     }  
    408.   
    409.       
    410.   
    411.     public Object  put(String key,Object value) {  
    412.         if(dataMap==null)  
    413.         {  
    414.             dataMap=new HashMap<String, Object>();  
    415.         }  
    416.         return dataMap.put(key, value);  
    417.     }  
    418.     public Object  get(String key,Object value) {  
    419.         if(dataMap==null)  
    420.         {  
    421.             dataMap=new HashMap<String, Object>();  
    422.         }  
    423.         return dataMap.get(key);  
    424.     }  
    425.   
    426.       
    427.     
    428. }  
    1. package demo2;  
    2.   
    3. import java.util.AbstractCollection;  
    4. import java.util.ArrayList;  
    5. import java.util.Collections;  
    6. import java.util.Iterator;  
    7. import java.util.LinkedList;  
    8. import java.util.List;  
    9. import java.util.Queue;  
    10. import java.util.Random;  
    11.   
    12. import demo2.Task.OnSystemFinishListen;  
    13. import demo2.Task.TaskStatus;  
    14.   
    15.   
    16. public class TaskQueue implements Runnable, OnSystemFinishListen {  
    17.     static String debug = "TaskQueue";  
    18.     @SuppressWarnings("unchecked")  
    19.     // 在等待的任务队列  
    20.      static LinkedList<Task> tasks_wait = new LinkedList<Task>();  
    21.   
    22.     public static class TaskQueueExpection extends Exception{  
    23.         TaskQueueExpection(String detailMessage) {  
    24.             super(detailMessage);  
    25.             // TODO Auto-generated constructor stub  
    26.         }  
    27.           
    28.     };  
    29.       
    30.     // 正在执行的任务  
    31.      static ArrayList<Task> tasks_running = new ArrayList<Task>();  
    32.     // 是否持续运行  
    33.     public static boolean isRun=true;  
    34.     // runnable保证线程安全  
    35.     private static TaskQueue runnable = new TaskQueue();;  
    36.     // 最大线程数  
    37.     static int ThreadMaxNum = 1;  
    38.   
    39.     public static TaskQueue getRunnable() {  
    40.         return runnable;  
    41.     }  
    42.   
    43.     // 如果队列线程为空或者停止则重新开启  
    44.     public static void serivesRun() {  
    45.         // TODO Auto-generated method stub  
    46.         boolean isCanSeriver=false;  
    47.         synchronized (tasks_running) {  
    48.             isCanSeriver=tasks_running.size() < ThreadMaxNum;  
    49.         }  
    50.        runnable.run();  
    51.     }  
    52.       
    53.     //获取正在执行的任务数  
    54.     public static int getRunningTaskCount() {  
    55.         synchronized (TaskQueue.tasks_running) {  
    56.             return TaskQueue.tasks_running.size();  
    57.         }  
    58.     }  
    59.     //设置最大任务数  
    60.     public static void setThreadMaxNum(int num) {  
    61.         TaskQueue.ThreadMaxNum = num<1?1:num>100?100:num;  
    62.     }  
    63.   
    64.     // 线程锁 如果等待队列的任务数不为空,并且当前线程数字少于最大线程数  
    65.     public static boolean taskRun() {  
    66.         synchronized (tasks_wait) {  
    67.             synchronized (tasks_running) {  
    68.                 return !tasks_wait.isEmpty()  
    69.                         && tasks_running.size() < ThreadMaxNum;  
    70.             }  
    71.         }  
    72.     }  
    73.     //开启新线程  
    74.     public void run() {  
    75.         // 线程锁 如果等待队列的任务数不为空,并且当前线程数字少于最大线程数  
    76.         Task newTask;  
    77.         while((newTask=getWaittingTask())!=null)  
    78.         {  
    79.             System.err.println("开启新线程处理一个新任务,ID:"+newTask.getTaskID());  
    80.             newTask.setOnSystemFinishListen(runnable);  
    81.             newTask.threadRun();  
    82.             newTask=null;  
    83.         }  
    84.          
    85.     }  
    86.       
    87.      //递归 避免新开线程   唤醒等待中的任务 但此方案会造成java.lang.StackOverflowError  
    88.      void notifyWaitingTask()  
    89.     {  
    90.         Task newTask;  
    91.         while((newTask=getWaittingTask())!=null)  
    92.         {  
    93.             System.err.println("唤醒旧线程处理一个新任务,ID:"+newTask.getTaskID());  
    94.             newTask.setOnSystemFinishListen(runnable);  
    95.             newTask.run();  
    96.             newTask=null;  
    97.         }  
    98.           
    99.     }  
    100.       
    101.     private  Task getWaittingTask()  
    102.     {  
    103.         Task t=null;  
    104.         //测试  
    105.         while (isRun && taskRun()) {  
    106.             // 添加带执行中动态数组中  
    107.             synchronized (tasks_wait) {  
    108.                 // 从等待任务的队列中获取并移除此列表的头(第一个元素)  
    109.                 t = tasks_wait.poll();  
    110.                 // 如果h为空则从队列重新取对象或者任务绑定的状态变化了  
    111.                 if (t == null || t.status == TaskStatus.without) {  
    112.                     System.out.println("任务取消 编号" + t!=null?String.valueOf(t.getTaskID()):"空任务");  
    113.                     continue;  
    114.                 }  
    115.             }  
    116.             synchronized (tasks_running) {  
    117.                 tasks_running.add(t);  
    118.             }  
    119.             System.out.println( "正在执行任务数" + tasks_running.size() + "/上限"  
    120.                     + ThreadMaxNum);  
    121.   
    122.             return t;  
    123.         }  
    124.         return t;  
    125.     }  
    126.       
    127.   
    128.     @Override  
    129.     public void OnSystemFinish(Task t, Object data) {  
    130.         // TODO Auto-generated method stub  
    131.         synchronized (tasks_running) {  
    132.             // 从处理中的动态数组中移除此任务  
    133.             tasks_running.remove(t);  
    134.             System.out.println( "执行队列中移除任务taskid=" + t.taskID);  
    135.             // 通知执行后续未处理的任务  
    136.             System.out.println("正在执行任务数" + tasks_running.size() + "/上限"  
    137.                     + ThreadMaxNum);  
    138.              
    139.             // 移除此名字映射  
    140.             if (t.getSingletonName() != null) {  
    141.                 Task.getNameTask().remove(t.getSingletonName());  
    142.             }  
    143.         }  
    144.           
    145.   
    146.     }  
    147.   
    148. }  


    Demo代码下载地址

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    HDFS HA高可用
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/4821404.html
Copyright © 2011-2022 走看看