JUC高并发编程(04) -- 线程间定制化通信

本文详细讲解了如何使用Java并发工具包中的ReentrantLock和Condition接口,实现实例化的线程间定制化通信,包括AA、BB和CC线程按顺序轮流打印。通过lock(), newCondition(), await(), signal()等方法协调多线程操作,确保任务按预期顺序执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JUC高并发编程

四、线程间定制化通信

4.1)线程间定制化通信案例

A线程打印2次AA,B线程打印4次BB,C线程打印6次CC,按照此顺序循环3轮

4.2)线程间定制化通信案例代码实现

4.2.1)Lock接口

public interface Lock {
    void lock();
​
    void lockInterruptibly() throws InterruptedException;
​
    boolean tryLock();
 
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
​
    void unlock();
​
    Condition newCondition();
}

4.2.1.1)lock()

lock()方法是平常使用得最多的一个方法,就是用来获取锁。

如果锁已被其他线程获取,则进行等待;采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。

因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。

通常使用Lock 来进行同步的话,是以下面这种形式去使用的:

Lock lock = new ReentrantLock();
//上锁 
lock.lock(); 
try{    
  //处理任务 
}catch(Exception ex){
   ...
}finally{
 //释放锁 
 lock.unlock();  
} 

4.2.1.2)newCondition

关键字synchronized与wait()/notify()这两个方法一起使用可以实现等待/通知模式,Lock锁的newContition()方法返回Condition对象,Condition类也可以实现等待/通知模式。

用notify()通知时,JVM会随机唤醒某个等待的线程,使用Condition类可以进行选择性通知,Condition比较常用的两个方法:

  1. await()会使当前线程等待,同时会释放锁,当其他线程调用signal()时,线程会重 新获得锁并继续执行;

  2. signal()用于唤醒一个等待的线程。

注意:在调用Condition的await()/signal()方法前,也需要线程持有相关的Lock锁,调用await()后线程会释放这个锁,在singal()调用后会从当前 Condition对象的等待队列中,唤醒一个线程,唤醒的线程尝试获得锁,一旦获得锁成功就继续执行。

4.2.2)代码实现

流程分析如下图:

代码如下:

package com.study.lock;
​
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
​
//第一步 创建资源类
class ShareResource {
    //定义标志位
    // 1 AA     2 BB     3 CC
    private int flag = 1;
​
    //创建Lock锁
    private Lock lock = new ReentrantLock();
​
    //创建三个condition
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();
    private Condition c3 = lock.newCondition();
​
    //打印2次,参数第几轮
    public void print2(int loop) throws InterruptedException {
        //上锁
        lock.lock();
        try {
            //判断:flag值是否是1,如果不是1,等待
            while (flag != 1) {
                //等待
                c1.await();
            }
            //干活:如果flag值是1,就输出信息
            for (int i = 1; i <= 2; i++) {
                System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + i + " :轮数:" + loop);
            }
            //通知:通知BB线程
            //修改标志位为 2 -> BB
            flag = 2;
            //通知BB线程
            c2.signal();
        } finally {
            //释放锁
            lock.unlock();
        }
    }
​
    //打印4次,参数第几轮
    public void print4(int loop) throws InterruptedException {
        lock.lock();
        try {
            //判断:flag值是否是2,如果不是2,等待
            while (flag != 2) {
                c2.await();
            }
            //干活:如果flag值是2,就输出信息
            for (int i = 1; i <= 4; i++) {
                System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + i + " :轮数:" + loop);
            }
            //通知:通知CC线程
            //修改标志位为 3 -> CC
            flag = 3;
            //通知CC线程
            c3.signal();
        } finally {
            lock.unlock();
        }
    }
​
    //打印6次,参数第几轮
    public void print6(int loop) throws InterruptedException {
        lock.lock();
        try {
            //判断:flag值是否是3,如果不是3,等待
            while (flag != 3) {
                c3.await();
            }
            //干活:如果flag值是3,就输出信息
            for (int i = 1; i <= 6; i++) {
                System.out.println("当前线程名:" + Thread.currentThread().getName() + " :: " + i + " :轮数:" + loop);
            }
            //通知:通知AA线程
            //修改标志位为 1 -> AA
            flag = 1;
            //通知AA线程
            c1.signal();
        } finally {
            lock.unlock();
        }
    }
}
​
public class ThreadDemo3 {
    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        // 创建线程 AA
        new Thread(() -> {
            // 循环调用 3 次
            for (int i = 1; i <= 3; i++) {
                try {
                    shareResource.print2(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();
        // 创建线程 BB
        new Thread(() -> {
            // 循环调用 3 次
            for (int i = 1; i <= 3; i++) {
                try {
                    shareResource.print4(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();
        // 创建线程 CC
        new Thread(() -> {
            // 循环调用 3 次
            for (int i = 1; i <= 3; i++) {
                try {
                    shareResource.print6(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "CC").start();
    }
}

输出:

com.study.lock.ThreadDemo3
当前线程名:AA :: 1 :轮数:1
当前线程名:AA :: 2 :轮数:1
当前线程名:BB :: 1 :轮数:1
当前线程名:BB :: 2 :轮数:1
当前线程名:BB :: 3 :轮数:1
当前线程名:BB :: 4 :轮数:1
当前线程名:CC :: 1 :轮数:1
当前线程名:CC :: 2 :轮数:1
当前线程名:CC :: 3 :轮数:1
当前线程名:CC :: 4 :轮数:1
当前线程名:CC :: 5 :轮数:1
当前线程名:CC :: 6 :轮数:1
当前线程名:AA :: 1 :轮数:2
当前线程名:AA :: 2 :轮数:2
当前线程名:BB :: 1 :轮数:2
当前线程名:BB :: 2 :轮数:2
当前线程名:BB :: 3 :轮数:2
当前线程名:BB :: 4 :轮数:2
当前线程名:CC :: 1 :轮数:2
当前线程名:CC :: 2 :轮数:2
当前线程名:CC :: 3 :轮数:2
当前线程名:CC :: 4 :轮数:2
当前线程名:CC :: 5 :轮数:2
当前线程名:CC :: 6 :轮数:2
当前线程名:AA :: 1 :轮数:3
当前线程名:AA :: 2 :轮数:3
当前线程名:BB :: 1 :轮数:3
当前线程名:BB :: 2 :轮数:3
当前线程名:BB :: 3 :轮数:3
当前线程名:BB :: 4 :轮数:3
当前线程名:CC :: 1 :轮数:3
当前线程名:CC :: 2 :轮数:3
当前线程名:CC :: 3 :轮数:3
当前线程名:CC :: 4 :轮数:3
当前线程名:CC :: 5 :轮数:3
当前线程名:CC :: 6 :轮数:3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值