單例模式
是多線程的一個案例,是一種常見的設計模式。
兩種實現單例模式的方法:
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);
}
}