java 多线程交替
要求:
甲线程:a、b、c、d、e
乙线程:1、2、3、4、5
丙线程:A、B、C、D、E
输出结果:a-1-A b-2-B c-3-C …
方法1:
在临界区使用一个数字代表当前执行的线程号,线程每打印一个字符就切换为下一个线程号
/**
* 3线程交替打印字符
* 注:每次当前线程打印完一个字符,就切换到下一个线程
* @author a_apple
* @create 2020-05-06 21:32
*/
class Resource {
private int current = 1;
/**
*
* 如果当前线程号 now!=current -->阻塞
* 否则 current = next -->切换下一次应该执行的线程号
* @param now 用来代表当前的执行线程
* @param next 用来代表下一个要执行的线程
*/
public void changeCurrent(int now, int next) {
//changeCurrent(1,2),三个线程交替的流程顺序
//changeCurrent(2,3),
//changeCurrent(3,1),
while (current != now) {
try {
wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//如果等于当前线程,那么执行完切换下一个
current = next;
notifyAll();
}
}
class SubThread implements Runnable {
private final Resource res;
private char[] arr;
private int now;
private int next;
private Thread t1;
/**
* 通过传参告知线程的执行顺序
*
* @param res 临界资源
* @param arr 需要被打印的字符数组
* @param now 当前要执行的线程(自身Demo对象
* @param next 下一个要执行的线程
*/
public SubThread(Resource res, char[] arr, int now, int next) {
this.res = res;
this.arr = arr;
this.now = now;
this.next = next;
t1 = new Thread(this);
}
@Override
public void run() {
//获取对象锁
synchronized (res) {
for (char c1 : arr) {
//切换下一个线程,并唤醒所有
//注意,不能打印后再切换,因为当前对象锁还没放,会继续打印2后,当前线程才阻塞。此时输出:1-2-a-
res.changeCurrent(now, next);
System.out.print(c1 + "-");
if(c1>='a')
System.out.println();
try {
//当前线程暂停0.5秒,但未放锁res
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void start() {
t1.start();
}
public void join() throws InterruptedException {
t1.join();
}
}
public class ThreadDemo {
public static void main(String[] args) throws Exception {
char[] c1 = {'1', '2', '3', '4', '5'};
char[] c2 = {'A', 'B', 'C', 'D', 'E'};
char[] c3 = {'a', 'b', 'c', 'd', 'e'};
//临界资源,初始
Resource res = new Resource();
SubThread t1 = new SubThread(res, c1, 1, 2);
SubThread t2 = new SubThread(res, c2, 2, 3);
SubThread t3 = new SubThread(res, c3, 3, 1);
t1.start();
t2.start();
t3.start();
}
}
输出:
1-A-a-
2-B-b-
3-C-c-
4-D-d-
5-E-e-
方法2:
使用Lock配合Condition实现精准唤醒,使线程有序进行
package pers.xu.multithread.question;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 使用精准唤醒打印交替打印字符
* @author a_apple
* @create 2020-05-25 9:09
*/
class PrintStore{
private Lock lock = new ReentrantLock();
private int num = 1;
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
public void printA(char ch){
lock.lock();
try {
if(num!=1){
conditionA.await();
}
System.out.print(ch+"-");
// 换标志唤醒B
num = 2;
conditionB.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB(char ch){
lock.lock();
try {
if(num!=2){
conditionB.await();
}
System.out.print(ch+"-");
// 换标志唤醒C
num = 3;
conditionC.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC(char ch){
lock.lock();
try {
if(num!=3){
conditionC.await();
}
System.out.print(ch+"\n");
// 换标志唤醒B
num = 1;
conditionA.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class AlterPrint {
public static void main(String[] args){
PrintStore store = new PrintStore();
char[] arrA = {'a','b','c','d','e'};
char[] arrB = {'1','2','3','4','5'};
char[] arrC = {'A','B','C','D','E'};
new Thread(()->{
for (int i = 0; i < arrA.length; i++) {
store.printA(arrA[i]);
}
}).start();
new Thread(()->{
for (int i = 0; i < arrB.length; i++) {
store.printB(arrB[i]);
}
}).start();
new Thread(()->{
for (int i = 0; i < arrC.length; i++) {
store.printC(arrC[i]);
}
}).start();
}
}
输出:
a-1-A
b-2-B
c-3-C
d-4-D
e-5-E