第四章:(1)线程间定制化通信

一、线程间定制化通信

  多个线程之间的执行时机并不是固定的,是由 CPU 来操作调度的,如果要让线程按照我们需要的顺序执行,这就是线程间定制化通信。

  

二、案例

1、题目要求

  三个线程之间按顺序调用,实现 A -> B -> C
  三个线程启动,要求如下:
  AA打印5次,BB打印10次,CC打印15次
  接着
  AA 打印5次,BB打印10次,CC打印15次
  ……进行10轮
 

2、思考:

  (1)有顺序通知,需要有标识位;
  (2)有一个锁 Lock,3把钥匙 Condition;
  (3)判断标识位;
  (4)输出线程名 + 第几次 + 第几轮;
  (5)修改标志位,通知下一个;
  

3、代码实现

//第一步:创建资源类
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();

    //打印5次,参数第几轮
    public void print5(int loop) throws InterruptedException {
        //上锁
        lock.lock();

        try {
            //第二步:判断    干活  通知

            //判断:防止虚假唤醒,使用 while 循环
            while (flag != 1) {
                c1.await();
            }

            //干活
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数:"+loop);
            }

            //通知
            flag = 2;     //修改标志位 2
            c2.signal();  //通知 BB 线程,唤醒 c2 等待的线程

        } finally {
            //解锁
            lock.unlock();
        }
    }

    //打印10次,参数第几轮
    public void print10(int loop) throws InterruptedException {
        //上锁
        lock.lock();

        try {
            //第二步:判断    干活  通知

            //判断:防止虚假唤醒,使用 while 循环
            while (flag != 2) {
                c2.await();
            }

            //干活
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数:"+loop);
            }

            //通知
            flag = 3;     //修改标志位 3
            c3.signal();  //通知 CC 线程,唤醒 c3 等待的线程

        } finally {
            //解锁
            lock.unlock();
        }
    }

    //打印15次,参数第几轮
    public void print15(int loop) throws InterruptedException {
        //上锁
        lock.lock();

        try {
            //第二步:判断    干活  通知

            //判断:防止虚假唤醒,使用 while 循环
            while (flag != 3) {
                c3.await();
            }

            //干活
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName()+" :: "+i+" :轮数:"+loop);
            }

            //通知
            flag = 1;     //修改标志位 1
            c1.signal();  //通知 AA 线程,唤醒 c1 等待的线程

        } finally {
            //解锁
            lock.unlock();
        }
    }
}

public class ThreadDemo3 {

    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();

        //创建多个线程,调用资源类的操作方法
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print5(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "AA").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print10(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "BB").start();

        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    shareResource.print15(i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "CC").start();
    }
}

三、多线程编程步骤

  第一步:创建资源类,在资源类创建数据和操作方法;

  第二步:在资源类操作方法
  (1)判断
  (2)干活
  (3)通知

  第三步:创建多个线程,调用资源类的操作方法;

  第四步:注意标志位的修改和定位;

原文地址:https://www.cnblogs.com/niujifei/p/15824325.html