简介
最近遇到一个面试题目,如何实现使用多个线程以固定顺序打印字母,例如线程A打印字母“A”,线程B打印线程字母“B”,线程C打印字母“C”,要求控制台打印的内容是ABCABC。。。
好久没有使用这个ReentrantLock对于它的方法的使用有些模糊了,这里回忆下顺便也能加深下记忆。
ReentrantLock方法介绍
- lock 获得锁资源,如果被其他线程获取,则阻塞等待
- lockInterruptibly 与lock的不同之处在于它等待锁资源时响应中断,抛出中断状态
- tryLock 立即获取锁,即使获取不到不阻塞
- newCondition 生成一个该锁资源的条件,可以支持完成Object 监控器(wait notify notifyAll)
Condition方法介绍
- await 等待被signalled或者被中断
- signal 唤醒一个等待的线程重新获取锁
- signalAll 唤醒所有等待的线程重新获取锁
实现
理解了这些方法那么实现就简单了,代码如下
package com.ee;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest {
private static ReentrantLock lock = new ReentrantLock();
private static Condition a = lock.newCondition();
private static Condition b = lock.newCondition();
private static Condition c = lock.newCondition();
private static AtomicInteger t = new AtomicInteger(0);
private static final int THREADS = 3;
public static void main(String[] args) {
ReentrantLockTest lockTest = new ReentrantLockTest();
ExecutorService pool = Executors.newFixedThreadPool(THREADS);
pool.execute(lockTest.new PrintTask(a, b, "A", 0));
pool.execute(lockTest.new PrintTask(b, c, "B", 1));
pool.execute(lockTest.new PrintTask(c, a, "C", 2));
}
class PrintTask implements Runnable {
//本线程的条件
private Condition me;
//下个线程的条件
private Condition next;
private String message;
private int index;
public PrintTask(Condition me, Condition next, String message, int index) {
this.me = me;
this.next = next;
this.message = message;
this.index = index;
}
@Override
public void run() {
while(true) {
try {
lock.lock();
while(t.get() % THREADS != index) {
try {
//不到本线程的时机,则等待
me.await();
} catch (InterruptedException e) {
if (Thread.interrupted()) {
e.printStackTrace();
}
}
}
System.out.print(message);
t.incrementAndGet();
//通知其他线程重新获取锁,该他们执行了
next.signalAll();
}finally {
lock.unlock();
}
}
}
}
}