Java基础知识之线程通信和相关面试题

一.实际中需要线程之间的协作,比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权。因为生产者如果不释放对临界资源的占用权,那么消费者就无法消费队列中的商品,就不会让队列有空间,那么生产者就会一直无限等待下去。因此,一般情况下,当队列满时,会让生产者交出对临界资源的占用权,并进入挂起状态。然后等待消费者消费了商品,然后消费者通知生产者队列有空间了。同样地,当队列空时,消费者也必须等待,等待生产者通知它队列中有商品了。这种互相通信的过程就是线程间的协作。
  Java中线程通信协作的最常见的两种方式:
  一.syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
  二.ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()
  线程间直接的数据交换:
  三.通过管道进行线程间通信:1)字节流;2)字符流

①syncrhoized加锁的线程的Object类的wait()/notify()/notifyAll()
线程通信-wait和notify方法介绍:
java.lang.Object类提供类两类用于操作线程通信的方法.
wait():执行该方法的线程对象释放同步锁,JVM把该线程存放到等待池中,等待其他的线程唤醒该线程.
notify:执行该方法的线程唤醒在等待池中等待的任意一个线程,把线程转到锁池中等待.
notifyAll():执行该方法的线程唤醒在等待池中等待的所有的线程,把线程转到锁池中等待.

注意:上述方法只能被同步监听锁对象来调用,否则报错IllegalMonitorStateException…

假设A线程和B线程共同操作一个X对象(同步锁),A,B线程可以通过X对象的wait和notify方法来进行通信,流程如下:
1:当A线程执行X对象的同步方法时,A线程持有X对象的锁,B线程没有执行机会,B线程在X对象的锁池中等待.
2:A线程在同步方法中执行X.wait()方法时,A线程释放X对象的锁,进入A线程进入X对象的等待池中.
3:在X对象的锁池中等待锁的B线程获取X对象的锁,执行X的另一个同步方法.
4:B线程在同步方法中执行X.notify()方法时,JVM把A线程从X对象的等待池中移动到X对象的锁池中,等待获取锁.
5:B线程执行完同步方法,释放锁.A线程获得锁,继续执行同步方法.

注意:
(1)同步锁池:
同步锁必须选择多个线程共同的资源对象.
当前生产者在生产数据的时候(先拥有同步锁),其他线程就在锁池中等待获取锁.
当线程执行完同步代码块的时候,就会释放同步锁,其他线程开始抢锁的使用权.

(2)多个线程只有使用相同的一个对象的时候,多线程之间才有互斥效果.
我们把这个用来做互斥的对象称之为,同步监听对象/同步锁.
同步锁对象可以选择任意类型的对象即可,只需要保证多个线程使用的是相同锁对象即可.
因为,只有同步监听锁对象才能调用wait和notify方法,所以,wait和notify方法应该存在于Object类中,而不是Thread类中.
在这里插入图片描述
在这里插入图片描述
②ReentrantLock类加锁的线程的Condition类的await()/signal()/signalAll()

Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition1的await()、signal()这种方式实现线程间协作更加安全和高效。因此通常来说比较推荐使用Condition,在阻塞队列那一篇博文中就讲述到了,阻塞队列实际上是使用了Condition来模拟线程间协作。

Condition是个接口,基本的方法就是await()和signal()方法;
Condition依赖于Lock接口,生成一个Condition的基本代码是lock.newCondition()
调用Condition的await()和signal()方法,都必须在lock保护之内,就是说必须在lock.lock()和lock.unlock之间才可以使用
  Conditon中的await()对应Object的wait();
  Condition中的signal()对应Object的notify();
  Condition中的signalAll()对应Object的notifyAll()。

在这里插入图片描述
面试题:
(1)sleep和wait区别?
答: sleep是Thread类的方法,wait是Object类中定义的方法
sleep() 是static静态的方法,他不能改变对象的机锁,当一个synchronized块中调用了sleep()方法,线程虽然进入休眠,但是对象的机锁没有被释放,其他线程依然无法访问这个对象。
wait()是Object类的方法,当一个线程执行到wait方法时,它就进入到一个和该对象相关的等待池,同时释放对象的机锁,使得其他线程能够访问,可以通过notify,notifyAll方法来唤醒等待的线程

(2)什么是生产者和消费者模式?
生产者消费者模式是通过一个阻塞队列来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,
而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,
阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

发布了99 篇原创文章 · 获赞 2 · 访问量 2615

猜你喜欢

转载自blog.csdn.net/weixin_41588751/article/details/105228237