用多线程顺序打印ABC多次?
问题描述:有三个线程顺序打印abc十次,请用线程同步实现。
1. synchronized锁 + 状态位
package com.fll.juc.interviews;
public class ThreadPrintABCSequential implements Runnable{
/**
* 问题描述:
* 有三个线程顺序打印abc十次,请用线程同步实现。
*/
private final int PRINT_COUNT = 10;
private static volatile int flag = 1; //这里必须要用static,不然打印的时候阻塞
private Object thisLock;
private char value;
public static void main(String[] args) throws InterruptedException {
Object thisLock = new Object();
new Thread(new ThreadPrintABCSequential(thisLock,'A')).start();
new Thread(new ThreadPrintABCSequential(thisLock,'B')).start();
new Thread(new ThreadPrintABCSequential(thisLock,'C')).start();
Thread.sleep(100);
}
/**
* @param thisLock 当前锁
* @param value 要打印的字符
*/
public ThreadPrintABCSequential(Object thisLock,char value) {
this.thisLock = thisLock;
this.value = value;
}
@Override
public void run(){
for (int i = 0; i < PRINT_COUNT; i++) {
if(value == 'A') {
//如果是要打印A,则线程A能拿到锁之后,BC线程都暂停打印一个A
synchronized(thisLock) {
while(flag != 1) {
try {
thisLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println('A');
flag = 2;
thisLock.notifyAll(); //提醒A线程开始
}
}else if(value == 'B') {
synchronized(thisLock) {
while(flag != 2) {
try {
thisLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println('B');
flag = 3;
thisLock.notifyAll(); //提醒B线程开始
}
}else if (value == 'C') {
synchronized(thisLock) {
while(flag != 3) {
try {
thisLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println('C');
flag = 1;
thisLock.notifyAll(); //提醒C线程开始
}
}
}
}
}
输出:
分析:flag用来标注下一个要打印的字符,如果是1,代表打印A;如果是2,代表打印B;如果是3,代表打印C;注意:flag必须要用static和volatile修饰
2. ReetrantLock + condition 其实思路和第一种类似
package com.fll.juc.interviews;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadPrintABCSequential_ReentrantLock implements Runnable{
/**
* 问题描述:
* 有三个线程顺序打印abc十次,请用线程同步实现。
*/
private final int PRINT_COUNT = 10; //打印次数
private static volatile int flag = 1; //这里必须要用static,不然打印的时候阻塞
private Lock lock; //锁对象
private Condition condition; //condition对象,负责处理线程状态
private char charValue; //打印字符
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
ThreadPrintABCSequential_ReentrantLock tReentrantLockA = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'A');
ThreadPrintABCSequential_ReentrantLock tReentrantLockB = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'B');
ThreadPrintABCSequential_ReentrantLock tReentrantLockC = new ThreadPrintABCSequential_ReentrantLock(lock,conditionA,'C');
//用线程池操作
ExecutorService pool = Executors.newFixedThreadPool(5); //创建一个默认线程数为5的线程池
pool.execute(tReentrantLockA);
pool.execute(tReentrantLockB);
pool.execute(tReentrantLockC);
Thread.sleep(100);
pool.shutdown();
}
@Override
public void run() {
try {
lock.lock();
for (int i = 0; i < PRINT_COUNT; i++) {
if(charValue == 'A') {
while( flag != 1 ) {
condition.await();
}
System.out.println(""+(i+1)+":"+charValue);
flag=2;
condition.signal();
}else if(charValue == 'B') {
while( flag != 2 ) {
condition.await();
}
System.out.println(""+(i+1)+":"+charValue);
flag=3;
condition.signal();
}else if(charValue == 'C') {
while( flag != 3 ) {
condition.await();
}
System.out.println(""+(i+1)+":"+charValue);
flag=1;
condition.signal();
}
}
}catch(Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public ThreadPrintABCSequential_ReentrantLock(Lock thisLock,Condition condition,char value){
this.lock = thisLock;
this.charValue = value;
this.condition = condition;
}
}
输出:
需要注意的是显示锁ReentrantLock需要用在try finally块内,最后必须释放锁。
try {
lock.lock();
//...
}catch(Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}