内存队列Demo
public class MyQueue {
private final static int MAX_SIZE = 100;
private LinkedList<String> queue = new LinkedList<String>();
/**
* 添加元素
*/
public synchronized void offer(String element) {
try {
if (queue.size() == MAX_SIZE) {
//一个线程只要执行到这一步了,就意味着这个线程获取到锁了
//当这个队列满了就可以让线程进入一个等待的状态,释放掉锁
wait();
}
queue.addLast(element);
//放入元素后,唤醒别的线程
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 获取元素
*/
public synchronized String take() {
String element = null;
try {
if (queue.size() == 0) {
wait(); //将锁释放掉,等待别的线程去执行放入数据的操作
}
element = queue.removeFirst();
notifyAll();//唤醒当前等待这个锁的线程
} catch (Exception e) {
e.printStackTrace();
}
return element;
}
}
wait和notify / notifyAll还是挺有用的,在多线程开发中,还是挺常见的,一般用来做线程通信,某个线程可以处于等待状态,其他线程可以来通知他唤醒他。
实际上wait和notify / notifyAll其实主要是用来控制线程的,和volatile、synchronzied也都是控制线程的
wait和notify底层原理
当线程调用了wait()时,当前线程被加入到实例对象中的C++锁对象wait set队列里,同时monitor计数器减一。
当别的线程调用了notifyAll()时,把waitset队列里的线程唤醒。
加锁的时候必须对同一个对象实例进行加锁,因为这两个方法操作的都是一个对象实例中的那个monitorObject,只有这样wait和notify操作的才是同一套东西
wait和notify注意事项
- wait
- wait与sleep的区别:前者释放锁,后者不释放锁
- wait(),必须是有人notify唤醒他,wait(timeout),阻塞一段时间,然后自己唤醒,继续争抢锁
- notify
- notify()与notifyall():前者就唤醒block状态的一个线程,后者唤醒block状态的所有线程
- wait与notify,必须在synchronized代码块中使用,因为必须是拥有monitor lock的线程才可以执行wait与notify操作。因此wait与notify,必须与synchornized一起,对同一个对象进行使用,这样他们对应的monitor才是一样的