线程间的通信
主要技术点:
- 使用wait/notify实现线程间的通信;
- 生产者消费者模式的实现;
- 方法join的使用
- ThreadLocal的使用
等待/通知机制
方法wait()的作用是使当前代码执行的线程进行等待,该方法将当前线程置入“欲执行队列”中。
方法notify()的作用是进行通知,由线程规划器挑选wait()的线程进行执行。wait()方法和notify()方法都需要在同步块下执行,否则会抛异常。同步代码块执行到wait()方法时,会立即释放对该代码块的锁,进行等待状态,执行到notify()方法时,notify()会发出通知到其他wait()线程,但是notify()方法所在的同步块不会立即释放锁。
- wait()方法:可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待状态,直到再次被唤醒;
- notify()方法:可以随机唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程推出等待队列,进入可运行状态,notify()方法仅通知一个线程;
- notifyAll()方法:使所有正在等待队列中等待同意共享资源的“全部”线程从等待状态退出,进入可执行状态。
1)新创建一个新的线程对象后,在调用它的start()方法,系统会为此线程分配CPU资源,使其处于Runnable(可运行)状态,如果抢到CPU资源就进入Running(运行)状态;
2)Runnable状态和Running状态可以相互切换,线程进入Runnable状态大体分为以下五种情况:
- 调用sleep()方法后经过的时间超过了指定的休眠时间;
- 线程调用的阻塞IO已经返回,阻塞方法执行完毕;
- 线程成功获得了试图同步的监视器;
- 线程正在等待某个通知,其他线程发出了通知;
- 处于挂起的线程调用了resume()恢复方法。
3)Blocked是阻塞的意思,阻塞状态结束后,线程进入Runnable状态,出现阻塞状态的情况:
- 线程调用sleep()方法,主动放弃占用的处理器资源;
- 线程调用了阻塞式IO方法,在该方法返回前,该线程被阻塞;
- 线程试图获得一个同步监视器,但该同步监视器被其他线程占有;
- 线程等待某个通知;
- 线程调用了suspend()方法,被挂起。
4)run()方法运行结束进入销毁阶段,整个线程执行完毕。
方法wait(long):带一个参数的wait方法的功能是等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。
管道流(pipeStream):管道流是一种特殊的流,用于在不同线程间直接传送数据。一个线程发送数据到输出管道,其他线程从输入管道中读取数据,通过使用管道实现不同线程之间的通信。
join()方法的使用:
等待线程对象销毁。方法join的作用是使所属的线程对象x正确执行run()方法中的任务,而使当前线程z进行无限期的阻塞,等待线程x销毁后在继续执行线程z后面的代码。
join(long)方法与wait(long)的区别:
- join(long)执行完之后释放锁;
- wait(long)执行完之后不释放锁。
类ThreadLocal的使用
类ThreadLocal主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。类ThreadLocal解决的是变量在不同线程之间的隔离性,也就是不同线程拥有自己的值,不同线程中的值是可以放入的ThreadLocal类中进行保存的。
类InheritedThreadLocal的使用
使用InherThreadLocal类可以在子线程中获取父线程继承下来的值。子线程可以对父线程的值进行更改,但是应当注意,如果子线程在取得值得同时,主线程将InheritedThreadLocal中得值进行更改,那么子线程取到的值还是旧值。