要实现多线程轮流打印,那么线程需要交替执行。如果是两个线程可以通过wait和notify来进行交替,但是如果用多个线程来交替,简单的wait和notify就不能满足需求了。
总数每加1,就要切换线程,首先线程启动后只要总数没有到1000,都是有机会去执行加1的,问题是线程需要判断自己该不该执行这个操作?
我们知道HashMap底层有一个数组(这里不讨论HashMap的底层具体细节),假设HashMap不扩容,那么数组长度此时是固定的,put时会对key值进行Hash计算,让key值落在数组的某一个位置上,也就是说不论key值是多少,总会落在数组上。
我们先来看一下最简单的Hash算法模数哈希(求余数),假设分子不固定,分母为3,那么余数只会有这些结果:0,1,2。也就是说余数是固定的,不管分子怎么变化,余数就会在这个范围内变化,如果分子是递增的,那么余数也是挨着轮询变化的,例如:
0%3=0, 1%3=1, 2%3=2, 3%3=0, 4%3=1, 5%3=2, 6%3=0
分子(递增):0,1,2,3,4,5,6
余数(轮询交替):0,1,2,0,1,2,0
那对应到程序里面来,变化的是总数count,而且count是递增的,不变的是线程总数threadTotal,那么我们可以通过count%threadTotal得到一个余数,这个余数值刚好可以作为一个线程的标识,那么我们就用这个值作为线程的threadId。那么count每增加1,就轮询切换得到一个threadId,实现了线程轮流交替。
那么线程怎么判断自己该不该执行加1操作呢,如果threadId == count % threadTotal为true,那么久可以确定线程有执行权利了。
思路有了,直接上代码。补充:可以不用加notifyAll和wait,但是加了是为了提高效率,因为我们的目的是多线程交替执行,如果不加wait,那么线程判断自己不满足执行条件后下次循环还可能抢到锁,也就是说不满足条件的情况可能频繁抢到锁,就浪费cpu资源了。
/**
* @author 蒋天文
* @date 2023年03月16日 4:28:44 PM
*/
public class TestMultiThread {
public static void main(String[] args) {
Thread t1 = new Thread(new CalculateTask());
Thread t2 = new Thread(new CalculateTask());
Thread t3 = new Thread(new CalculateTask());
Thread t4 = new Thread(new CalculateTask());
t1.start();
t2.start();
t3.start();
t4.start();
}
}
class CalculateTask implements Runnable {
private static volatile int count = 0;
private static int threadTotal;
private final int threadId;
public CalculateTask() {
this.threadId = threadTotal;
threadTotal++;
}
@Override
public void run() {
while (count < 100) {
synchronized (CalculateTask.class) {
if (count % threadTotal == threadId) {
count++;
System.out.println("线程:" + threadId + ",对数加了1,结果为:" + count);
CalculateTask.class.notifyAll();
} else {
try {
CalculateTask.class.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
}