内存队列Demo

  1. public class MyQueue {
  2. private final static int MAX_SIZE = 100;
  3. private LinkedList<String> queue = new LinkedList<String>();
  4. /**
  5. * 添加元素
  6. */
  7. public synchronized void offer(String element) {
  8. try {
  9. if (queue.size() == MAX_SIZE) {
  10. //一个线程只要执行到这一步了,就意味着这个线程获取到锁了
  11. //当这个队列满了就可以让线程进入一个等待的状态,释放掉锁
  12. wait();
  13. }
  14. queue.addLast(element);
  15. //放入元素后,唤醒别的线程
  16. notifyAll();
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. /**
  22. * 获取元素
  23. */
  24. public synchronized String take() {
  25. String element = null;
  26. try {
  27. if (queue.size() == 0) {
  28. wait(); //将锁释放掉,等待别的线程去执行放入数据的操作
  29. }
  30. element = queue.removeFirst();
  31. notifyAll();//唤醒当前等待这个锁的线程
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. return element;
  36. }
  37. }

wait和notify / notifyAll还是挺有用的,在多线程开发中,还是挺常见的,一般用来做线程通信,某个线程可以处于等待状态,其他线程可以来通知他唤醒他。
实际上wait和notify / notifyAll其实主要是用来控制线程的,和volatile、synchronzied也都是控制线程的

wait和notify底层原理

当线程调用了wait()时,当前线程被加入到实例对象中的C++锁对象wait set队列里,同时monitor计数器减一。
当别的线程调用了notifyAll()时,把waitset队列里的线程唤醒。
加锁的时候必须对同一个对象实例进行加锁,因为这两个方法操作的都是一个对象实例中的那个monitorObject,只有这样wait和notify操作的才是同一套东西
image.png

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才是一样的