Java多线程读书笔记(三)

来源:互联网 发布:caffe bias term false 编辑:程序博客网 时间:2024/06/05 03:53

线程间的通信

等待/通知机制

1.wait() notify()使用条件?

必须在同步方法或同步块中调用。如果没有适当的锁,就会抛异常:java.lang.IllegalMonitorException。(没有同步加锁)

2.使用notify()注意事项

notify方法执行后并不会立即释放锁,而是要等到该线程代码执行完之后才会释放。wait()和notify()所在同步代码块需要是同一个“对象监视器”才可以。

3.api解释?

  • wait():使当前执行的代码的线程进行等待,并释放锁。
  • notify():该通知用来通知那些可能等待该对象锁的其他线程,如果有多个线程等待,那么由线程规划器随机挑出一个。执行完后不会立即退出,等待执行notify()的线程将方法执行完之后,当前线程才会释放锁。
  • notifyAll():通知当前等待的所有线程。

4.可以在线程wait()时interupt()它吗?

会抛异常InterruptedException。

5.等待wait的条件发生变化( if 和 while )

    当有多个线程进入等待状态准备被唤起时,判断是否wait()的语句不该是if语句,而该改为while语句。假设两个消费者线程用if语句判断出当前无商品可消费,进入wait();某生产者线程生产了一个商品,然后NotifyAll()了。消费者A争抢到了锁,消费了这个商品,释放锁。消费者B发起争抢,得到了该锁,摩拳擦掌准备消费商品,然后……索引溢出,报错了。
    那么,怎么防止这种异常呢?消费者在抢到锁,被唤醒后,是不是可以再次对当前有无商品这个条件做判断,如果现在有商品,就消费;没有,就等待。所以,使用while()语句对wait条件进行判断,想必是极好的。

6.多生产者-多消费者问题中的假死问题如何解决?

    假死问题:线程进入“waiting”状态,就是假死。这里的假死问题就是指现在所有的线程都进入了“waiting”状态,不再执行任何业务功能了。
出现这种情况的原因是什么?明明有notify()啊。

线程中有阻塞队列等待执行队列,线程执行wait()后进入阻塞队列,被notify()后就从阻塞队列调到等待执行队列,准备争抢控制权(锁)。

代码中使用了wait()/notify()模式,线程之间可以通信,但是不保证线程唤醒的是异类。假设当前有生产者a,生产者b,消费者1,消费者2。四个线程全部start,即在等待执行队列,准备随时去抢锁。假设线程执行的顺序是:
-消费者1得到锁,无商品,进入阻塞队列;
-消费者2得到锁,无商品,进入阻塞队列;
-生产者1得到锁,无商品,生产商品,notify()后,再次判断有商品,进入阻塞队列;
-生产者2得到锁,有商品,释放锁,进入阻塞队列;
好了,大家都进入阻塞队列了。生产者1唤醒了生产者2,随后两人进入阻塞,没有线程是在等待执行队列。
解决这个问题就是把生产者和消费者中的notify()该为notifyAll(),这样就不会出现假死情况,程序一直执行下去。

7.通过管道进行线程通信。

1)PipedInputStream和PipedOutputStream;
2)PipedReader和PipedWriter
使用inputStream.connect(outputStream)和outputStream.connect(inputStream)。

方法join的使用

1.join的作用?

join的作用:等待线程对象销毁。使所属线程对象x正常执行完run方法中的任务,而对当前线程进行无限期的阻塞,等待线程x销毁后再继续执行当前线程的代码。
join()和Interrput()方法遇到会报异常。join(long)设定等待的时间。

2.join()和sleep()的区别?

查看join方法的源码,可以看见join方法是由wait()方法实现的。当执行wait()方法后,当前线程的锁被释放,其他线程可以调用此线程的同步方法了。但是sleep()方法不会释放锁。

类ThreadLocal的使用

类TheadLocal提供方法让每个线程绑定自己的值。InheritableThreadLocal可以在子线程中取得从父类继承下来的值。

PS:本篇内容属于读书笔记,非常感谢高洪岩老师的《Java多线程编程的核心技术》。这本书非常实用,易懂。如果涉及任何侵权行为,请尽快告诉我。