單例模式,阻塞隊列,定時器

單例模式

是多線程的一個案例,是一種常見的設計模式。

兩種實現單例模式的方法:
1、餓漢模式
2、懶漢模式

在這裏插入圖片描述
在這裏插入圖片描述

阻塞隊列

是一個先進先出的隊列
入隊列的時候如果發現隊列滿了,就會阻塞,直到有其他線程出隊列後,才能繼續如對類。
出隊列時候如果發現隊列空了,也會阻塞,直到有其他線程入隊列後,才能繼續出隊列。

public class ThreadDemo3 {
    static class BlockingQueue {
        //基於數組實現
        private int[] array = new int[1000];
        private int head = 0;
        private  int tail = 0;
        private int size = 0;

        public  void put(int value) throws InterruptedException {
            synchronized (this) {
                if (size == array.length) {
                    wait();
                }
                array[tail] = value;
                tail++;
                if (tail == array.length) {
                    tail = 0;
                }
                size++;
                notify();
            }
        }

        public  int take() throws InterruptedException {
            int ret = -1;
            synchronized (this) {
                if (size == 0) {
                    wait();
                }
                 ret = array[head];
                head++;
                if (head == array.length) {
                    head = 0;
                }
                size--;
                notify();
            }
            return ret;
        }
    }

    public static void main(String[] args) {
        BlockingQueue blockingQueue = new BlockingQueue();
        Thread producer = new Thread() {
            @Override
            public void run() {
                for (int i = 0;i<10000;i++) {
                    try {
                        blockingQueue.put(i);
                        System.out.println("生產成功"+i);
                        sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        };
        producer.start();
        Thread consumer = new Thread() {
            @Override
            public void run() {
                while (true) {
                    try {
                        int ret = blockingQueue.take();
                        System.out.println("消費元素"+ret);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        };
        consumer.start();
    }
}

代碼中,假如吧notify改爲notifyAll,被等待的線程全都被喚醒,這時假如一個線程出隊列結束後,隊列爲空,下個線程再去出隊列時,就會發生邏輯錯誤。這時,只需要把判斷數組是否爲空,或者是否滿的時候,把if字句改爲while循環,這時,當多個線程競爭鎖,消費者1先獲取到鎖,隊列爲空就返回來,再次執行while由於生產者生產了一個元素過來,size不爲空,循環推出,消費者1就可以執行後面的出隊列操作了,然後釋放鎖,當消費者2獲取到鎖後,wait也返回了,再次執行while,由於剛纔的元素已經取走了,size還是爲0,循環繼續執行調用wait,繼續等,就不會出現上述的邏輯錯誤,所以之後優先考慮while。

定時器

好比一個鬧鐘,有些邏輯,並不想立刻執行,而是需要等一定時間後再來執行。

定時器構成:
1.使用一個Task類來描述“一段邏輯”(一個要執行的任務),同時也要記錄這個任務在啥時候來執行。
2.使用一個阻塞優先隊列來組織若干個Task。
3.還需要一個掃描線程,掃描線程要循環檢測隊首元素是否需要執行,如果需要執行,就執行這個任務。

import java.util.concurrent.PriorityBlockingQueue;

class Task implements Comparable<Task>{
    //用runnable中的run方法來描述這個任務是啥
    public Runnable command;
    public long time;

    public Task(Runnable command, long after) {
        this.command = command;
        this.time = System.currentTimeMillis()+after;
        //相對時間,毫秒級別的時間戳
    }
    public void run() {
        command.run();
    }

    @Override
    public int compareTo(Task o) {
        return (int)(this.time-o.time);
    }
}
class Worker extends Thread {
    public PriorityBlockingQueue<Task> queue = null;

    public Worker( PriorityBlockingQueue<Task> queue) {

        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Task task = queue.take();
                long curTime = System.currentTimeMillis();
                if (task.time>curTime) {
                    queue.put(task);
                }else {
                    task.run();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }

        }
    }
}
class Timer {

    public PriorityBlockingQueue<Task> queue = new PriorityBlockingQueue<>();
    public Timer() {
        Worker worker = new Worker(queue);
        worker.start();
    }
    public void schedule(Runnable command,long after) {
        Task task = new Task(command,after);
        queue.put(task);
    }



}

public class ThreadDemo4 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hehe");
                timer.schedule(this,2000);
            }
        },2000);
    }

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