简易消息队列
-
编写queue
/** * 注: * 该简易队列中,put和get方法存在递归调用。 * 因为:如果我们的队列长度为3,当多个线程都达到3的时候都会进入等待状态,然后消费者调用get方法的时候,会唤醒put线程,这时候因为cpu上下文切换,就会出现size被执行多次 ++ 操作。这样,当size的值大于队列长度,就会出现size == data.length无法进入的情况,然后size则会出现无限累加递增。 * 但是加上递归之后,会对该队列方法继续加锁,而且操作的是同一个队列,这样就可以继续占用这把锁,其他线程等待,一次次添加锁的标记,这样就不会出现多线程上下文切换导致数据错乱的问题。 * 需要了解锁,非静态加锁,锁的是对象,静态加锁,锁的是字节码类。 * * 下图附加递归方法和不加递归方法的运行结果 */ public class MyQueue { String[] data = new String[3]; private int putIndex = 0; private int getIndex = 0; private int size = 0; public synchronized void put(String element) { //当队列存满,需要等待消费者消费 if (size == data.length) { try { System.out.println(Thread.currentThread().getName() + ":满了满了,等下!!!"); wait(); //3 } catch (InterruptedException e) { e.printStackTrace(); } put(element); return; } put0(element); } private void put0(String element) { //给队列赋值 data[putIndex] = element; //队列有数据,则唤醒get()的等待线程 notify(); System.out.println(Thread.currentThread().getName() + ":put唤醒!!!" + size); //每次插入消息后角标加一 ++putIndex; //如果角标达到队列的最大长度,需要赋值为0,从头开始 if (putIndex == data.length) { putIndex = 0; } //通过size记录每次数组队列在存满消息时等待 ++size; } public synchronized String get() throws InterruptedException { //size=0则没有消息,需要等待 if (size == 0) { try { wait(); System.out.println(Thread.currentThread().getName() + ":消费没了,喀喀喀!!!"); } catch (InterruptedException e) { e.printStackTrace(); } return get(); } return get0(); } private String get0() throws InterruptedException { Thread.sleep(500); String result = data[getIndex]; System.out.println(Thread.currentThread().getName() + ":get唤醒!!!" + size); notify(); ++getIndex; if (getIndex == data.length) { getIndex = 0; } --size; return result; } }
-
编写提供者,向队列存入消息
public class ProviderThread extends Thread { private MyQueue myQueue; public ProviderThread(MyQueue myQueue) { this.myQueue = myQueue; } @Override public void run() { int i = 1; while (true) { try { String tmp = "线程名:" + Thread.currentThread().getName() + ",提供者提工消息:" + i++; myQueue.put(tmp); System.out.println(tmp); Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
编写消费者,从队列读取消息
public class ConsumerThread extends Thread { private MyQueue myQueue; public ConsumerThread(MyQueue myQueue){ this.myQueue = myQueue; } @Override public void run() { while (true){ try { String result = myQueue.get(); System.out.println("线程名:" + Thread.currentThread().getName() + ",消费者消费的消息:" + result); Thread.sleep(600); } catch (InterruptedException e) { e.printStackTrace(); } } } }
-
编写启动类
public class QueueMain { public static void main(String[] args) throws InterruptedException { //一个队列,每个线程向队列里面插入消息 MyQueue myQueue = new MyQueue(); for (int i = 0; i < 3 ; i++) { Thread.sleep(100); new ProviderThread(myQueue).start(); } for (int i = 0; i < 1; i++) { new ConsumerThread(myQueue).start(); } // Thread.sleep(10000); // System.exit(0); } }
-
未加递归之前
-
添加递归之后
-