1. 程式人生 > >高併發程式設計:併發Queue介面

高併發程式設計:併發Queue介面

佇列是一種先進先出或者後進後出的資料結構。在此我們模擬一下佇列這種資料結構:
MyQueue.java定義如下:

public class MyQueue {

    //佇列的容器
    private LinkedList<Object> list = new LinkedList<Object>();

    //計數器 int count
    private final AtomicInteger count = new AtomicInteger(0);

    //最大容量
    private int maxSize;

    //最小容量
    private int  minSize = 0;

    //鎖
    private final Object lock = new Object();

    public MyQueue() {
        this(16);
    }

    public MyQueue(int maxSize) {
        this.maxSize = maxSize;
    }

    public void put(Object obj) {
        synchronized (lock) {
            while(count.get() == maxSize) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            list.add(obj); //將新的元素新增到容器裡
            System.out.println("新增前容器長度:" + count.get());
            count.getAndIncrement();
            System.out.println("新增後容器長度:" + count.get());
            lock.notify(); //喚醒執行緒
        }
    }

    public Object take() {
        Object temp = null;
        synchronized (lock) {
            while(count.get() == minSize) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            temp = list.removeFirst(); //從容器中移除第一個元素
            System.out.println("自減之前的長度:" + count.get());
            count.getAndDecrement();
            System.out.println("自減之後的長度:" + count.get());
            lock.notify();
        }
        return temp;
    }

    public int size() {
        return count.get();
    }

    public List<Object> getQueueList() {
        return list;
    }
}

該佇列的資料結構為一個List< Object> 作為容器來盛裝資料,此外還有幾個變數,分別是count計數器和maxSize,minSize最大最小容量的標誌,此外還有lock鎖。此類有3個核心方法,分別是size()返回佇列長度的方法,take()移除節點方法和put()新增節點方法。

該佇列的測試類定義如下:

public class TestMyQueue {

    public static void main(String[] args) throws Exception {
        MyQueue queue = new MyQueue(5);
        queue.put("A");
        queue.put("B");
        queue.put("C");
        queue.put("D");
        queue.put("E");
        System.out.println("主執行緒queue : " + queue);

        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                queue.put("F");
                queue.put("G");
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    queue.take();

                    Thread.sleep(1000);
                    queue.take();
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t2");

        t1.start();

        Thread.sleep(1000);
        t2.start();
        Thread.sleep(5000);
        List<Object> elements = queue.getQueueList();
        for(Object obj : elements) {
            System.out.print(obj.toString() + " ");
        }
    }
}

該測試類除了main函式所在的主執行緒之外還存在兩個子執行緒t1,t2。執行緒t1負責向容器大小為5的佇列容器放入"F"和"G"元素,執行緒t2則負責向佇列移除頭部節點。
輸出結果如下:

主執行緒queue : [email protected]
C D E F G