题目要求
实现一个互评打分过程:
- 创建一个线程池,为每个Employee开启一个线程。开启一个主持人线程;
- 主持人线程在按照顺序确定当前给谁打分,并通知所有的Employee线程(10个);Employee线程接到通知后,在随机延时后打出一个随机分数;主持人收集到所有人打出的分数后,计算出被评分人的平均分。
思路分析
采用ReentrantLock实现“等待-通知”机制
代码实现
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(THREAD_NUMBER);
// 开启主持人线程
executorService.execute(new CompereThread());
// 开启各个Employee线程
for (int index = 1; index <= EMPLOYEE_NUMBER; index++) {
executorService.execute(new EmployeeThread());
}
// 关闭线程池
executorService.shutdown();
}
}
public class Resource {
// 总线程数目
protected static final int THREAD_NUMBER = 11;
// 参与打分的员工数目
protected static final int EMPLOYEE_NUMBER = 10;
// 总分数
protected static float sumGrades = 0;
// 每轮已经打分的人数
protected static int sumEmployee = 0;
// 锁
protected static Lock lock = new ReentrantLock();
// 条件队列1:Employee线程使用
protected static Condition queue1 = lock.newCondition();
// 条件队列2:主持人线程使用
protected static Condition queue2 = lock.newCondition();
// 本次互评是否结束
protected static boolean finished = false;
}
// 主持人线程
public class CompereThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(CompereThread.class);
@Override
public void run() {
// 主持人尝试获得锁(获得与否其实不影响,即使获得了锁,当条件不满足时,即:还有员工没有打分,同样被挂起而释放锁)但是await方法必须在lock 和 unlock之间使用
lock.lock();
try {
for (int index = 1; index <= EMPLOYEE_NUMBER; index++) {
logger.info("【---第{}轮打分开始!---】", index);
// 等待所有人打分完毕 wait-notify机制
while (sumEmployee != EMPLOYEE_NUMBER) {
// 条件不满足 主持人线程挂起 释放锁 等待Employee们打分
queue2.await();
}
// 条件满足 所有人打分完毕 继续
// 计算平均分并打印
logger.info("【Employee{}的平均分为:{}", index, (sumGrades / EMPLOYEE_NUMBER));
logger.info("【---第{}轮打分结束!---】", index);
logger.info(" ");
// 初始化 为下一轮打分做准备
sumGrades = 0;
sumEmployee = 0;
// 本轮打分结束 唤醒所有Employee开始下一轮打分
queue1.signalAll();
}
} catch (Exception e) {
}
// 互评结束
finished = true;
// 手动释放锁
lock.unlock();
}
}
// 子员工线程
public class EmployeeThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(EmployeeThread.class);
private static final int MAX_GRADE = 10;
private static final int MAX_SLEEP_TIME = 3;
@Override
public void run() {
float grade = 0;
int cnt = 0;
// 互评过程未结束
try {
while (!finished) {
cnt++;
// 加锁 保证对各个线程 sumGrades 和 sumEmployee 操作的原子性和可见性
lock.lock();
// 竞争到锁 打分
// 随机延时 1-3s
TimeUnit.SECONDS.sleep((new Random().nextInt(MAX_SLEEP_TIME) + 1));
// 随机打分 1-10分
grade = (new Random().nextInt(MAX_GRADE) + 1);
sumGrades += grade;
// 本轮已打分人数更新
sumEmployee++;
// 打印每轮次的打分信息
logger.info("【Employee: {}】给第{}个工作人员打分为:{}——【当前总分】{} ", Thread.currentThread().getName(), cnt, grade, sumGrades);
// 本轮是否结束
if (sumEmployee >= EMPLOYEE_NUMBER) {
// 唤醒主持人线程开始下一轮
queue2.signal();
}
// 当前线程本轮打分结束 挂起 释放锁 本轮其他未打分线程去竞争 也防止重复打分
queue1.await();
}
} catch (Exception e) {
} finally {
// 手动释放
lock.unlock();
}
}
}