04:线程通信

Posted xmingzi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04:线程通信相关的知识,希望对你有一定的参考价值。

实现线程间通讯的方法:
    1:文件共享    2:网络共享(共享网络资源)    3:共享变量    4:JDK提供的线程协调API(wait/notify , park/unpark)
1:文件共享:
        通过向同一个文件写数据和读数据的形式共享信息。
        技术图片
2:变量共享:
         通过写和读同一个内存对象的形式共享数据。
 技术图片

 

 

3:线程协作API
        多线程协作经典的例子:生产者消费者模型。(主要就是配合实现:线程阻塞、线程唤醒)    
    技术图片
    被弃用的线程方法:suspend 和 resume。作用是挂起线程和恢复线程。
            弃用原因:容易写出死锁的代码(suspend方法挂起线程时不会释放锁)。
            例如:1:如果消费者被挂起之前拿到了锁,然而生产者需要拿到锁才能通知消费者去消费,出现死锁。
                       2:如果resume 的执行在前面,suspend的执行在后面。先发出了唤醒通知,但是没收到,挂起之后就再也没有收到唤醒通知。
    推荐使用的方法
        wait/notify 和 park/unpark。
                wait/notify : 当前线程等待。其实是将当前线程加入到了锁对象的等待集合中,并放弃当前持有的对象锁。必须先拿到对象锁才能调用(所以代码要在同步代码块中执行)
                notify/notifyAll:唤醒一个或者唤醒所有等待这个对象锁的线程。
                注意:1:wait导致线程进入等待状态时会释放锁但是如果notify执行在了wait之前。同样会导致线程永远等待。
                           2:wait方法是基于监视器实现的。
public void waitNotifyTest()throws Exception{
    new Thread(()->{
        // 不满足消费条件,进入等待
       while(true){  // 为了防止伪唤醒,所以使用while来判断
           synchronized (this){
               try {
                   System.out.println("进入线程,并等待。");
                   this.wait();
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
       }
        System.out.println("消费");
    }).start();
    // 暂停3秒,模拟生产
    Thread.sleep(3000);
    synchronized (this){
        // 通知消费者,可以终止等待了。
        this.notify();
    }
}
        park 和 unpark
                park和unpark机制是一个许可机制。
                    调用park方法:等待许可(如果许可已经存在,则直接就可以获取到)。
                    调用unpark:为指定线程提供许可。
                    注意:1:由于只是查看许可是否存在:所以park 和 unpark是可以不考虑先后顺序的。
                               2:park不会释放锁。如果带锁的线程park了。那么别的线程也就拿不到这个锁了。所以要注意同步代码中使用park的问题。
public void parkUnparkTest() throws Exception{
    Thread consumerThread = new Thread(() ->{
        while(true){ // 为了防止伪唤醒,所以使用while来判断
            System.out.println("消费条件不满足,线程进入等待");
            LockSupport.park(); // 将本线程进入挂起状态,但是不会释放锁。
        }
    });
    consumerThread.start();
    // 停3秒,模拟生产者已经生产完成。
    Thread.sleep(3000);
    // 通知消费线程,可以开始消费。
    LockSupport.unpark(consumerThread);
   伪唤醒:
     什么是伪唤醒:线程并非是收到api调用而唤醒的,而实应为更加底层的原因导致的。
     由于CPU调度的原因,等待中的线程可以会收到伪唤醒,程序会在没有满足条件的情况下激活等待的线程。这个时候如果使用的是if做为判断。那么程序就直接运行完。
  技术图片

 

 

以上是关于04:线程通信的主要内容,如果未能解决你的问题,请参考以下文章

片段通信问题(尝试调用虚方法)

BottomSheetDialogFragment 如何与其宿主片段通信?

Motan在服务provider端用于处理request的线程池

在tablayout片段之间进行通信[重复]

与另一个片段通信的片段接口

与线程通信并找到运行时间