本文记录学习多线程之间的任务调度,在面试中我们也经常会碰到线程循环打印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
先看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();
}
}