EP35-线程协作

昨天说的线程同步的场景是,多个线程想要同时操作一个对象,容易发生错乱;

现在有一种新的场景,两个线程要共享某个数据对象,跟前面不同的是,这里线程A负责给这个对象增加数据,线程B负责给这个对象减少数据。比如定义一个ArrayList对象listList <Object> list = new ArrayList<>();Thread A负责list.add(object),Thread B负责消耗list里的数据:

Object object = list.get(0);
list.clear();//拿到数据之后清空list

这就是一个「生产者-消费者」形式。

在这个基础上,需求是,仅当list里面没有数据,A才往里面add;仅当list里面有数据,B才从里面get、clear。亦即list里面只有0或1个object。也就是说我们希望list里面没有数据的时候,B是阻塞的,A是就绪的;反之A是就绪的,B是阻塞的。这就需要线程之间的协作

实现这种场景不仅需要synchronized,还需要waitnotify。注意waitnotify必须在synchronized内部用。

get数据的代码在下面;注意里面的wait()notify(),前几集提到过,wait()是SDK的Object类的native方法,描述成:

让当前线程一直等着,直到另一个线程为这个对象执行notify()/notifyAll()方法。跟wait(0)一个效果。
Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.

public synchronized Object getObject()
 {   
  while (list.size() == 0) {      
  try {
         wait();     
    } catch (InterruptedException e) 
    {
   e.printStackTrace();
  }   
 }         
   Object object = list.get(0);
   list.clear();
   notify();// 唤醒阻塞队列的某线程到就绪队列
   System.out.println("got it!");
   return object;
}

add数据的代码也类似,就是把list.get和下面的clear替换成list.add。
这样一来,两个线程同时执行上面两个不同方法,就不会发生冲突了,永远是add--->get--->add--->get..这样的顺序。

注意到上面检查list里面是否有数据的时候,无论是addObject还是getObject方法都用的是while而不是if,这不禁让人疑惑,既然这个wait()是一直阻塞到有人notify为止,为什么还要不停地判断是否需要wait呢?有人给出的解释是:
某些特定的情况下,线程有可能被假唤醒,使用while会循环检测更稳妥。

-Jan 10

Reference:
[1]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 32,453评论 18 399
  • 1.解决信号量丢失和假唤醒 public class MyWaitNotify3{ MonitorObject m...
    Q罗阅读 4,446评论 0 1
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 11,946评论 0 62
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,486评论 11 349
  • 名词解释 session 会话,维护用户状态。会话中关联了用户信息。 token 令牌,用于签权。 很多人纠结于t...
    dylanhuang88阅读 10,082评论 0 53

友情链接更多精彩内容