本文记录学习多线程之间的任务调度,在面试中我们也经常会碰到线程循环打印ABCD这样的面试题,接下来用代码进行实践,本文使用lock接口进行实现

 线程操作资源类,首先在资源类中定义一个可重入锁,以及4个绑定条件 ,

// 创建一个重入锁
    private Lock lock = new ReentrantLock();

    // 创建4个绑定
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private Condition condition4 = lock.newCondition();

    //  1 2 3 4 表示 ABCD 4个线程
    int number = 1;

 线程之间循环调用 A > B > C > D > A 

java线程中打印不了日志 java线程打印连续的abc_java线程中打印不了日志

先看A线程打印A,然后唤醒B线程

public void printA() {
        lock.lock();
        try {
            // 判断
            while (number != 1) {
                // 不等于1,需要等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "线程打印:\t A");
            // 唤醒 (干完活后,需要通知B线程执行)
            number = 2;
            // 通知 2 号去干活了
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

   同理B线程打印B,然后通知C线程, C线程打印C,然后通知D线程,到D线程这里,打印D后,然后通知A线程,完成一次循环,D线程打印唤醒A如下

public void printD() {
        lock.lock();
        try {
            // 判断
            while (number != 4) {
                // 不等于4,需要等待
                condition4.await();
            }

            System.out.println(Thread.currentThread().getName() + "线程打印:\t D");

            // 唤醒 (干完活后,需要通知A线程执行)
            number = 1;
            // 通知1号去干活了
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

我们每个线程执行5次,查看打印的结果

new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printA();
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printB();
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printC();
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printD();
            }
        }, "D").start();

查看结果

A线程打印:	 A
B线程打印:	 B
C线程打印:	 C
D线程打印:	 D
A线程打印:	 A
B线程打印:	 B
C线程打印:	 C
D线程打印:	 D
A线程打印:	 A
B线程打印:	 B
C线程打印:	 C
D线程打印:	 D
A线程打印:	 A
B线程打印:	 B
C线程打印:	 C
D线程打印:	 D
A线程打印:	 A
B线程打印:	 B
C线程打印:	 C
D线程打印:	 D

Process finished with exit code 0

整个类如下

package com.qx.boot.trm.utils;


import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @version V1.0
 * @author: hqk
 * @date: 2020/12/30 13:36
 * @Description:  线程循环调用
 */

class ShareResource {

    // 创建一个重入锁
    private Lock lock = new ReentrantLock();

    // 创建4个绑定
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();
    private Condition condition3 = lock.newCondition();
    private Condition condition4 = lock.newCondition();

    //  1 2 3 4 表示 ABCD 4个线程
    int number = 1;

    public  void printA() {
        lock.lock();
        try {
            // 判断
            while (number != 1) {
                // 不等于1,需要等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName() + "线程打印:\t A");
            // 唤醒 (干完活后,需要通知B线程执行)
            number = 2;
            // 通知2号去干活了
            condition2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printB() {
        lock.lock();
        try {
            // 判断
            while (number != 2) {
                // 不等于2,需要等待
                condition2.await();
            }

            System.out.println(Thread.currentThread().getName() + "线程打印:\t B");

            // 唤醒 (干完活后,需要通知C线程执行)
            number = 3;
            // 通知3号去干活了
            condition3.signal();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void printC() {
        lock.lock();
        try {
            // 判断
            while (number != 3) {
                // 不等于3,需要等待
                condition3.await();
            }

            System.out.println(Thread.currentThread().getName() + "线程打印:\t C");

            // 唤醒 (干完活后,需要通知D线程执行)
            number = 4;
            // 通知4号去干活了
            condition4.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }


    public void printD() {
        lock.lock();
        try {
            // 判断
            while (number != 4) {
                // 不等于4,需要等待
                condition4.await();
            }

            System.out.println(Thread.currentThread().getName() + "线程打印:\t D");

            // 唤醒 (干完活后,需要通知A线程执行)
            number = 1;
            // 通知1号去干活了
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
public class Test {

    public static void main(String[] args) {
        ShareResource shareResource = new ShareResource();
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printA();
            }
        }, "A").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printB();
            }
        }, "B").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printC();
            }
        }, "C").start();

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                shareResource.printD();
            }
        }, "D").start();

    }
}