一、使用wait,notify,notifyAll
1、使用场景:在多线程环境下,有时候一个线程的执行,依赖于另外一个线程的某种状态的改变,这个时候,我们就可以使用wait与notify或者notifyAll
2、注意点:
1)wait与sleep的区别:wait会释放持有的锁,而sleep不会,sleep只是让线程在指定时间内休眠,不去抢占CPU的资源
2)wait notify必须放在同步代码块中,且必须拥有当前对象的锁,即哪个对象wait,就调用哪个对象的notify
3)notify随机唤醒一个等待的线程;而notifyAll唤醒所有在该对象上等待的线程
二、使用管道流方式
1、使用场景:以内存为媒介,用于线程间的数据传输。主要有面向字节:【PipedOutputStream、PipedInputStream】、面向字符【PipedReader、PipedWriter】
2、示例:创建两个类,分别为Main类和Reader类;Main类作为一个线程输入数据,Reader类作为线程读取主线程的数据
三、使用Thread.join通信
1、使用场景:线程A执行到一半,需要一个数据,这个数据需要线程B去执行修改,只有B修改完成之后,A才能继续操作线程A的run方法里面,调用线程B的join方法,这个时候,线程A会等待线程B运行完成之后,再接着运行
2、示例:先运行线程2,运行到一半开始运行线程1,等待线程1完成后继续运行线程2
四、使用 ThreadLocal
1、使用场景:线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。每个线程单独存放一份变量副本
一般用的比较多的是
1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。
2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。
3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。
4、ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。
2、示例:创建两个线程实现自增
由结果可以看出:只要线程处于活动状态并且ThreadLocal实例可访问,那么每个线程都拥有对其本地线程副本的隐式引用变量;一个线程消失后,它的所有副本线程局部实例受垃圾回收(除非其他存在对这些副本的引用)
五、使用Condition
1、使用场景:可以在一个锁里面,存在多种等待条件
2、singal()方法用于唤醒一个在等待中的线程。相对的singalAll()方法会唤醒所有在等待中的线程。这和方式一的Obejct.notify()方法类似。
condition.await()方法必须在lock.lock()与lock.unlock()方法之间调用。与Object.wait()方法类似