一. synchronized 实现线程通讯
什么是线程通讯,可以将线程分为生产者线程与消费者线程,生产者线程创建共享数据(写),给消费者线程使用(读) 实现线程通讯的基本流程
多个线程操作的资源类 提供判断当前该生产还是消费的标识 生产线程执行,会判断当前是否该生产,不需要,当前线程进入休眠状态,否则执行生产,生产完毕后唤醒消费线程进行消费 消费线程执行,会判断当前是否该消费,不需要,当前线程进入休眠状态,否则执行消费,消费完毕后唤醒生产线程继续生产
wait() 与 notify() 方法讲解
wati() 与 notify() 是 Object 总服务类提供的方法, wati() 与 notify() 使用前提是在 synchronized 中 wati() 表示休眠并释放锁资源, notify() 表示唤醒当前此对象监视器上(同一锁下的)其它休眠线程
wait() 与 join() 的区别: wait() 用在 synchronized 中, 被 wait() 的线程需要唤醒, 在一个方法中调用了 join(),表示当前线程进入阻塞状态,并且在其它线程执行完毕后才会自动唤醒执行,没有锁的概念 wait() 与 sleep() 的区别: sleep 指定休眠时间,时间过后自动唤醒,并且sleep不会释放锁 notify() 与 yield()区别: yield() 使当前线程重新回到可执行状态,但是并不会马上执行,没有锁的概念,notify() 是唤醒被 wait() 的线程,与 wait() 配合使用的
代码示例
多线程同时操作的资源类,注意点在判断标识时不可以使用 if 判断,因为一个线程在进入if 后进行了阻塞,后续再唤醒时,不会再去判断一遍,会造成生产消费,不一致的情况,使用 while 进行判断,当有线程进入 while 中被阻塞,在后续被唤醒会再执行一次 while,再去判断一次
class MyResource {
private Integer num = 0 ;
public synchronized void production ( ) throws Exception {
while ( num != 0 ) {
this . wait ( ) ;
}
num++ ;
System. out. println ( "执行生产" + num) ;
this . notify ( ) ;
}
public synchronized void consumer ( ) throws Exception{
while ( num == 0 ) {
this . wait ( ) ;
}
num-- ;
System. out. println ( "执行消费" + num) ;
this . notify ( ) ;
}
}
多线程执行生产,消费测试
public class T1 {
public static void main ( String[ ] args) {
MyResource resource = new MyResource ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i< 50 ; i++ ) {
resource. production ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "A" ) . start ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i< 50 ; i++ ) {
resource. consumer ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "B" ) . start ( ) ;
}
}
二. Lock + Condition 实现线程通讯
在生产或消费执行时,首先获取到 Lock 锁, 判断标识当前不可以生产,或消费时,通过 Condition 调用 await() 方法设置当前线程进入阻塞状态,相当于 wait() 当生产或消费完毕后通过 Condition 调用 signal() 唤醒其它线程 注意点: 防止发送异常 Lock 锁无法释放问题,在 finally 中释放锁
代码示例
多线程操作的资源类
class MyResource {
private Integer num = 0 ;
private Lock lock = new ReentrantLock ( ) ;
private Condition condition = lock. newCondition ( ) ;
public void production ( ) throws Exception {
lock. lock ( ) ;
try {
while ( num != 0 ) {
condition. await ( ) ;
}
num++ ;
System. out. println ( "执行生产" + num) ;
condition. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
public void consumer ( ) throws Exception{
lock. lock ( ) ;
try {
while ( num == 0 ) {
condition. await ( ) ;
}
num-- ;
System. out. println ( "执行消费" + num) ;
condition. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
}
多线程生产消费执行测试
public class T1 {
public static void main ( String[ ] args) {
MyResource resource = new MyResource ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i< 50 ; i++ ) {
resource. production ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "A" ) . start ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i< 50 ; i++ ) {
resource. consumer ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "B" ) . start ( ) ;
}
}
Lock + Condition 实现线程通讯的优点
问题: 在前面的生产消费测试中,会发现,A线程生产完毕后,B线程消费,假设同时存在 C 生产线程,生产出的数据要指定的 D线程消费,问题是生产线程执行完毕后如何精准通知到指定的消费线程进行消费 解决问题,可以创建多个 Condition,一个 Condition 对应线程,当前指定的生产或消费线程在不可以执行时使用指定的 Condition 调用 await() 进入阻塞,当生产或消费完毕后使用指定的 Condition 调用 signal() 唤醒对应的线程 多线程操作的资源类,提供多个 Condition,通过指定的 Condition 在方法中指定进行指定休眠,指定唤醒
class MyResource {
private Integer num = 0 ;
private Lock lock = new ReentrantLock ( ) ;
private Condition conditionA = lock. newCondition ( ) ;
private Condition conditionB = lock. newCondition ( ) ;
private Condition conditionC = lock. newCondition ( ) ;
private Condition conditionD = lock. newCondition ( ) ;
public void production ( ) throws Exception {
lock. lock ( ) ;
try {
while ( num != 0 ) {
conditionA. await ( ) ;
}
num++ ;
System. out. println ( "A执行生产" + num) ;
conditionB. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
public void productionC ( ) throws Exception {
lock. lock ( ) ;
try {
while ( num != 0 ) {
conditionC. await ( ) ;
}
num++ ;
System. out. println ( "C执行生产" + num) ;
conditionD. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
public void consumerB ( ) throws Exception {
lock. lock ( ) ;
try {
while ( num == 0 ) {
conditionB. await ( ) ;
}
num-- ;
System. out. println ( "B执行消费" + num) ;
conditionA. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
public void consumerD ( ) throws Exception {
lock. lock ( ) ;
try {
while ( num == 0 ) {
conditionD. await ( ) ;
}
num-- ;
System. out. println ( "D执行消费" + num) ;
conditionC. signal ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
lock. unlock ( ) ;
}
}
}
多线程生产,消费运行测试
public class T1 {
public static void main ( String[ ] args) {
MyResource resource = new MyResource ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i < 3 ; i++ ) {
resource. production ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "A" ) . start ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i < 3 ; i++ ) {
resource. consumerB ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "B" ) . start ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i < 3 ; i++ ) {
resource. productionC ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "C" ) . start ( ) ;
new Thread ( ( ) - > {
try {
for ( int i = 0 ; i < 3 ; i++ ) {
resource. consumerD ( ) ;
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
} , "D" ) . start ( ) ;
}
}