Java/Android中 隊列的實現方案

package com.bisien.test.application;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Queen {
    public static void main(String[] args) {
        System.out.println("--------------------- " + Thread.currentThread().getName());
// 這裏暫時只開一個窗口。
        TaskQueue taskQueue = new TaskQueue(1);
        taskQueue.start();
        for (int i = 0; i < 10; i++) {
            PrintTask task = new PrintTask(i);
            taskQueue.add(task);
        }
//        隊裏的打印狀況按照我們理想的狀態打印出來了
// 我的id是:0 ThreadName :Thread-0
//我的id是:1 ThreadName :Thread-0
//我的id是:2 ThreadName :Thread-0
//我的id是:3 ThreadName :Thread-0
//我的id是:4 ThreadName :Thread-0
//我的id是:5 ThreadName :Thread-0
//我的id是:6 ThreadName :Thread-0
//我的id是:7 ThreadName :Thread-0
//我的id是:8 ThreadName :Thread-0
//我的id是:9 ThreadName :Thread-0






//        如果開啓多個窗口的話,第一個買票人,去第一個窗口買票,第二個人去第二個窗口買票,第三個人去第三個窗口買票,第四個人進去排在第一位,
//        當第一、第二、第三、窗口中不論哪一個窗口辦完事後(假設買票),第四個人就去那個窗口辦事(假設買票),第五個人等待,一次類推,這樣子就
//        達到隊列同時併發三個任務的效果

//        上面這個就是一個普通隊列,其他一些特性也就是在此基礎上進行封裝的,那麼下面我就在此基礎上加上任務優先級,也就說我們說的特殊窗口---> 軍人優先

    }
    public static class PrintTask implements ITask{
        private int id;
        public PrintTask(int id) {
            this.id = id;
        }
        public void run() {
            // 爲了儘量模擬窗口辦事的速度,我們這裏停頓兩秒。
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ignored) {
            }
            System.out.println("我的id是:" + id + " ThreadName :" + Thread.currentThread().getName());
        }
    }

    //    辦事的人(假設購買火車票)
    public interface ITask {
        //        具體要辦的事
        void run();
    }

    //    窗口(火車站窗口),也就是給買火車票的人辦事
    public static class TaskExecutor extends Thread {
        //      窗口排的隊,這個對隊裏面全是買火車票的人
        private BlockingQueue<ITask> taskQueue;
        //        判斷當前窗口是否開放,true 表示開放
        private boolean isRunning = true;

        public TaskExecutor(BlockingQueue<ITask> taskQueue) {
            this.taskQueue = taskQueue;
        }

        @Override
        public void run() {
            while (isRunning) {
                ITask iTask;
                try {
                    iTask = taskQueue.take();//叫下一個人進來買票
//                   take() 當隊列中的item爲空的時候,它會一直處於阻塞狀態,當隊列中的進入item的時候,他會立即返回一個值
//                   (所以我們把它放入到一個Thread 中,以避免阻塞調用它的線程,Android中可能是ui線程)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    if (!isRunning) {
//                        發生意外,並且如果窗口已經關閉,
                        interrupt();
                        break;
                    }
//                    發生意外,不是窗口還是開着(也就是營業的狀態)
                    continue;//那麼久繼續等待
                }
//                爲這個人買票
                iTask.run();
//                退出當前線程
//                quit();
            }

        }

        //        下班
        public void quit() {
            isRunning = false;
            interrupt();
        }
    }

    //    辦事的人(買票人)和窗口都有了(火車站售票窗口),我們封裝一個隊列,某機構
    public static class TaskQueue {
        //        某機構排的隊,隊裏買火車票的人
        private BlockingQueue<ITask> mTaskQueue;
        //        好多窗口
        private TaskExecutor[] mTaskExecutors;

        // 在開發者new隊列的時候,要指定窗口數量。
        public TaskQueue(int size) {
            mTaskQueue = new LinkedBlockingQueue<>();// 如果開啓多個窗口的的話,共享一羣人
            mTaskExecutors = new TaskExecutor[size];
        }

        //        開始上班
        public void start() {
            stop();//開啓之前先停止
            // 把各個窗口都打開,讓窗口開始上班。
            for (int i = 0; i < mTaskExecutors.length; i++) {
//                創建n 條線程,然後開啓
                mTaskExecutors[i] = new TaskExecutor(mTaskQueue);
                mTaskExecutors[i].start();
            }
        }

        public void stop() {
            if (mTaskExecutors != null){
                for (TaskExecutor taskExecutor : mTaskExecutors) {
                    if (taskExecutor != null) taskExecutor.quit();
                }
            }
        }
        public <T extends ITask> int add(T task){
            if(!mTaskQueue.contains(task)){
                mTaskQueue.add(task);
            }
            // 返回排的隊的人數,公開透明,讓外面的人看的有多少人在等着辦事。
            return mTaskQueue.size();
        }
    }

}

------------------------------------------------------下面是實現隊列的優先級----------------------------------------------------

package com.bisien.test.application;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

//優先級隊列
public class PriorityQueen {
    public static void main(String[] args) {
        System.out.println("--------------------- " + Thread.currentThread().getName());
//        如果開啓多個窗口的話,第一個買票人,去第一個窗口買票,第二個人去第二個窗口買票,第三個人去第三個窗口買票,第四個人進去排在第一位,
//        當第一、第二、第三、窗口中不論哪一個窗口辦完事後(假設買票),第四個人就去那個窗口辦事(假設買票),第五個人等待,一次類推,這樣子就
//        達到隊列同時併發三個任務的效果

//        上面這個就是一個普通隊列,其他一些特性也就是在此基礎上進行封裝的,那麼下面我就在此基礎上加上任務優先級,也就說我們說的特殊窗口---> 軍人優先

        TaskQueue taskQueue = new TaskQueue(1   );
        taskQueue.start();

        // 爲了顯示出優先級效果,我們預添加3個在前面堵着,讓後面的優先級效果更明顯。
        taskQueue.add(new PrintTask(110));
        taskQueue.add(new PrintTask(112));
        taskQueue.add(new PrintTask(122));
        for (int i = 0; i < 10; i++) {
            PrintTask task = new PrintTask(i);
            if (1 == i) {
                task.setPriority(Priority.LOW); // 讓第2個進入的人最後辦事。
            } else if (8 == i) {
                task.setPriority(Priority.HIGH); // 讓第9個進入的人第二個辦事。
            } else if (9 == i) {
                task.setPriority(Priority.Immediately); // 讓第10個進入的人第一個辦事。
            }
            taskQueue.add(task);
        }
    }

    public static class PrintTask implements ITask {
        // 默認優先級。
        private Priority priority = Priority.DEFAULT;
        private int id;

        public PrintTask(int id) {
            this.id = id;
        }

        public void run() {
            // 爲了儘量模擬窗口辦事的速度,我們這裏停頓兩秒。
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ignored) {
            }
            System.out.println("我的id是:" + id + " ThreadName :" + Thread.currentThread().getName());
        }

        @Override
        public void setPriority(Priority priority) {
            this.priority = priority;
        }

        @Override
        public Priority getPriority() {
            return priority;
        }

        private int sequence;

        @Override
        public void setSequence(int sequence) {
            this.sequence = sequence;
        }

        @Override
        public int getSequence() {
            return sequence;
        }

        @Override
        public int compareTo(ITask another) {
            final Priority me = this.getPriority();
            final Priority it = another.getPriority();
//            System.out.println("me : " + me.name() + "---------it :" + it.name() + " -----id : " + id);

//            compareTo(E)中傳進來的E是另一個Task,如果當前Task比另一個Task更靠前就返回負數,如果比另一個Task靠後,那就返回正數,如果優先級相等,那就返回0。
//            return me == it ? this.getSequence() - another.getSequence() : it.ordinal() - me.ordinal();
//           返回的數是0代表兩個元素相同,正數說明大於,負數說明小於
            return me == it ? 0 : it.ordinal() - me.ordinal();
        }
    }

    //    我們首先讓task 有一個優先級的標識,所以我用一個枚舉類,來標記優先級
    public enum Priority {
        LOW,//最低
        DEFAULT,//默認級別
        HIGH,//高於默認級別
        Immediately //立刻執行
    }

    //    辦事的人(假設購買火車票),這個等級肯定要給我們辦事的人,也就是Task
    public interface ITask extends Comparable<ITask> {
        //具體要辦的事
        void run();

        void setPriority(Priority priority);

        Priority getPriority();

        void setSequence(int sequence);

        int getSequence();
    }

    //    窗口(火車站窗口),也就是給買火車票的人辦事
    public static class TaskExecutor extends Thread {
        //      窗口排的隊,這個對隊裏面全是買火車票的人
        private BlockingQueue<ITask> taskQueue;
        //        判斷當前窗口是否開放,true 表示開放
        private boolean isRunning = true;

        public TaskExecutor(BlockingQueue<ITask> taskQueue) {
            this.taskQueue = taskQueue;
        }

        @Override
        public void run() {
            while (isRunning) {
                ITask iTask;
                try {
                    iTask = taskQueue.take();//叫下一個人進來買票
//                   take() 當隊列中的item爲空的時候,它會一直處於阻塞狀態,當隊列中的進入item的時候,他會立即返回一個值
//                   (所以我們把它放入到一個Thread 中,以避免阻塞調用它的線程,Android中可能是ui線程)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    if (!isRunning) {
//                        發生意外,並且如果窗口已經關閉,
                        interrupt();
                        break;
                    }
//                    發生意外,不是窗口還是開着(也就是營業的狀態)
                    continue;//那麼久繼續等待
                }
//                爲這個人買票
                iTask.run();
//                退出當前線程
//                quit();
            }

        }

        //        下班
        public void quit() {
            isRunning = false;
            interrupt();
        }
    }

    //    辦事的人(買票人)和窗口都有了(火車站售票窗口),我們封裝一個隊列,某機構
    public static class TaskQueue {
        //        某機構排的隊,隊裏買火車票的人
        private BlockingQueue<ITask> mTaskQueue;
        //        好多窗口
        private TaskExecutor[] mTaskExecutors;
        //
        private AtomicInteger mAtomicInteger = new AtomicInteger();

        // 在開發者new隊列的時候,要指定窗口數量。
        public TaskQueue(int size) {
//            這裏我們需要把LinkedBlockingQueue 替換成PriorityBlockingQueue<E> 因爲它可以自動做到優先級的比較,
//            也就是我們的Task必須要實現 Comparable<E> 接口
            mTaskQueue = new PriorityBlockingQueue<>();// 如果開啓多個窗口的的話,共享一羣人
            mTaskExecutors = new TaskExecutor[size];
        }

        //        開始上班
        public void start() {
            stop();//開啓之前先停止
            // 把各個窗口都打開,讓窗口開始上班。
            for (int i = 0; i < mTaskExecutors.length; i++) {
//                創建n 條線程,然後開啓
                mTaskExecutors[i] = new TaskExecutor(mTaskQueue);
                mTaskExecutors[i].start();
            }
        }

        public void stop() {
            if (mTaskExecutors != null) {
                for (TaskExecutor taskExecutor : mTaskExecutors) {
                    if (taskExecutor != null) taskExecutor.quit();
                }
            }
        }

        public <T extends ITask> int add(T task) {
            if (!mTaskQueue.contains(task)) {
//                mAtomicInteger.incrementAndGet() 每次都會自增一,相當於這個方法:mAtomicInteger.addAndGet(1);
                task.setSequence(mAtomicInteger.incrementAndGet()); // 注意這行。
                mTaskQueue.add(task);
            }
            // 返回排的隊的人數,公開透明,讓外面的人看的有多少人在等着辦事。
            return mTaskQueue.size();
        }
    }

}

參考:https://blog.csdn.net/u012062455/article/details/78247234

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章