线程间的通信:wait,notify,notifyAll方法的使用与详解

线程间的通信是为了在获取共享资源时不发生死锁,主要是用到Object类的wait,notify,notifyAll方法来实现的,接下来我们来认识它们的使用。

目录
一,2个线程的通信:wait,notify
wait方法:
notify方法
一,2个线程的通信:wait,notify
我们实现一个同步队列,这个队列有3种状态:

1.队列为空时,获取线程不能获取要进行阻塞
2.队列为满时,存入线程不能存入要进行阻塞
3.有存入数据都是队列没有满时,
代码:

  1. public class EventQueue{
  2. private final int max;
  3. static class Event{
  4. }
  5. private final LinkedList<Event> eventQueue=new LinkedList<Event>();
  6. private final static int DEFUALT_MAX_EVENT=10
  7. public EventQueue(){
  8. this(DEFUALT_MAX_EVENT);
  9. }
  10. public EventQueue(int max){
  11. this.max=max;
  12. }
  13. public void offer(Event event){
  14. synchronized(eventQueue){
  15. if(eventQueue.size>=max){
  16. eventQueue.wait();
  17. }
  18. eventQueue.addLast(event);
  19. eventQueue.notify();
  20. }
  21. }
  22. public Event take(){
  23. synchronized(eventQueue){
  24. if(eventQueue.isEmpty){
  25. eventQueue.wait();
  26. }
  27. Event event eventQueue.removeFirst();
  28. eventQueue.notify();
  29. return event
  30. }
  31. }
  32. }

上面的代码时是这样的,但offer时,发现队列已经满了,就阻塞这个线程,然后释放所有获取到的资源,让其他线程进行争夺,如果队列没有满时,添加到后面,并把其他阻塞的一条线程唤醒(notify),take方法也是这样的意思

wait方法:
1.wait方法有3个重载方法,分别是:wait(),wait(long timeout),wait(long timeout,int nanos);
2.Object的wait方法 会导致当前线程进入阻塞,直到有其他线程用notify或者notifyAll方法唤醒,或者时间到了自动唤醒。
3.wait方法必须有该对象的monitor,也就是说wait方法只能在同步代码中用。
4.一旦执行了wait方法,会释放当前monitor的所有资源,也就是说会解锁,释放所有资源,让其他线程争夺。
notify方法
唤醒单个正在执行wait方法的线程,如果有就唤醒,没有就算了,被唤醒的线程还是要重新开始争夺锁。

注意事项:

wait方法可以被其他线程调interrupt中断,中断后会接收到错误,并删除interrupt标识。
wait方法和notify要在同步代码中使用,跟sleep有区别。
wait方法和notify的对象要和当前同步代码的monitor,因为每个monitor都有自己的wait set,如果不一样,会发生错误。
如:
错误案例一,没有在同步代码中

  1. private final LinkedList<Event> eventQueue=new LinkedList<Event>();
  2. public void offer(Event event){
  3. if(eventQueue.size>=max){
  4. eventQueue.wait();
  5. }
  6. eventQueue.addLast(event);
  7. eventQueue.notify();
  8. }

错误案例二,monitor对象不一样:synchronized的monitor是this,而wait是eventQueue对象的,notify同理。

  1. private final LinkedList<Event> eventQueue=new LinkedList<Event>();
  2. public synchronized void offer(Event event){
  3. if(eventQueue.size>=max){
  4. eventQueue.wait();
  5. }
  6. eventQueue.addLast(event);
  7. eventQueue.notify();
  8. }

这些都会抛出IllegalMonitorStateException异常信息。

最后:
如果是多个存入线程或者多个获取线程,把notify改成notifyAll,因为notify只能唤醒一个,而notifyAll可以唤醒所有当前被阻塞的线程。