需求
A\B\C三个线程轮执行3次,A退出,之后BC轮替执行2次,B退出,C执行2次退出,整个过程A执行3次,B执行5次,C执行7次
执行效果
A第1次执行
B第1次执行
C第1次执行
A第2次执行
B第2次执行
C第2次执行
A第3次执行
==>A次数达到,退出
B第3次执行
C第3次执行
B第4次执行
C第4次执行
B第5次执行
==>B次数达到,退出
C第5次执行
C第6次执行
C第7次执行
==>C次数达到,退出
TERMINATED
TERMINATED
TERMINATED
实现
static class AlternateRun implements Runnable{
static Lock lock = new ReentrantLock();
static List<Condition> queue = new ArrayList<>(10);
static volatile int cursor = 0;
static Condition expected= null;
Condition condition;
Consumer<Integer> consumer;
int times = 0;
/**
* @param consumer 执行的方法
* @param times 执行次数
*/
public AlternateRun(Consumer<Integer> consumer,int times){
condition = lock.newCondition();
this.consumer = consumer;
this.times = times;
queue.add(condition);
}
@Override
public void run() {
//
for (int i = 1; i <= times; i++) {
try {
fuck(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void fuck(int count) throws InterruptedException {
lock.lock();
//检测是否是预期线程 ,不是则将线程挂起
System.out.println(cursor);
while((expected=queue.get(cursor))!=condition) {
condition.await();
}
//执行回调
consumer.accept(count);
//当集合只有一个元素时(此时只有一个线程,则不需要signal、await)
if(count<times&&queue.size()==1) {
return;
}
//次数未满,wait把锁让出,唤醒下一个
if(count<times) {
waitAndSignalNext();
}
//次数到了则移除,唤醒下一个
else if(count==times){
System.out.println("==>"+Thread.currentThread().getName()+"次数达到,退出");
removeAndSignalNext();
}
lock.unlock();
}
static void waitAndSignalNext() throws InterruptedException {
if(cursor==queue.size()-1) {
queue.get(cursor=0).signal();;
}else {
queue.get(++cursor).signal();;
}
expected.await();
}
static void removeAndSignalNext() {
if(cursor==queue.size()-1) {
queue.get(cursor=0).signal();
}else {
queue.get(cursor+1).signal();
}
queue.remove(expected);
}
}
测试代码
Consumer<Integer> fn = (count)->{
System.out.println(Thread.currentThread().getName()+"第"+count+"次执行");
};
AlternateRun s = new AlternateRun(fn,3);
AlternateRun s2 = new AlternateRun(fn,5);
AlternateRun s3 = new AlternateRun(fn,7);
Thread t1 = new Thread(s,"A");
Thread t2 = new Thread(s2,"B");
Thread t3 = new Thread(s3,"C");
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
System.out.println(t1.getState());
System.out.println(t2.getState());
System.out.println(t3.getState());