韩雯雯,皮蛋豆腐的做法,世界地图

admin 8个月前 ( 03-25 17:59 ) 0条评论
摘要: 通过N个线程顺序循环打印从0至100,如给定N=3则输出:thread0:0thread1:1thread2:2thread0:3thread1:4。...

背景

在前几天,群里有个群友问了我一道面试阿里的时候遇到的多线程题目,这个题目比较有意思,在这里和大家分享一下。

废话不多说,直接上题目:

通过N个线程顺序循环打印肥臀从0至100,如给定N=3则输出:
thread0: 0
thread1: 1
thread2: 2
thread冷艳居0: 3
thread1: 4
.....

一些经常刷面试题的朋友,之前肯定遇到过下面这个题目:

两个线程交替打印0~100的奇偶数:
偶线程:0
奇线程:1
偶线程:2
奇线程:3

这两个题目看起来相似,第二个题目稍微来说比金怡云较简单一点,大家可以先思考一下两个线程奇偶数如何打印。

两线程奇偶数打印

有一些人这里可能会用讨巧的,用一个线程进行循环,在每次循环里面都会做是奇数还是偶数的判断,然后打印出这个我们想要的结果。在这里我们不过多讨论这种违背题目本意的做法。

其实要做这个题目我们就需要控制两个线程的执行顺序,偶线程执行完之后奇数线程执行,这个有点像通知机制,偶线程通知奇线程,奇线程再通知偶线程。而一看到通知/等待,立马就有朋友想到了Object中的wait和notify。没错,这里我们用wait和notify对其进行实现,代码如下:

public class 交替打印奇偶数 {
static class SoulutionTask im妈妈和女儿plements Runnable{
static int value = 0;
@Override
public很想吃掉你 void run() {
while (value <= 100){
synchronized (SoulutionTask.class){
System.out.println(Thread.currentThread().getName() + ":" + value++);
SoulutionTask.class.notify();
try {
SoulutionTask.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) {
new Thread(new SoulutionTask(), "偶数").start();
new Thread(new SoulutionTask(), "奇数").start();
}
}

这里我们有两个线程,通过notify和wait用来控制我们线程的执行,从而打印出我们目标的结果

N个线程循环打印

再回到我们最初的问题来,N个线程进行循环打印,这个问题我再帮助群友解答了之后,又再次把这个问题在群里面抛了出来,不少老司机之前看过交替打印奇偶数这道题目,于是马上做出了几个版本,让我们看看老司机1的代码:

public class 老司机1 implements Runnable {
private static final Object LOCK = new Object();
/**
* 当前即将打印的数字
*/
private static int current = 0;
/**
* 当前线程编号,从0开始
*/
private int threadNo;
/**
* 线程数量
*/
private int threadCount;
/**
* 打印的最大数值
*/
private int maxInt;
public 老司机1(int threadNo, int threadCount, int maxInt) {
this.threadNo = threadNo;
this.threadCount = threadCount;嫂子黄瓜
this.maxInt = maxInt;
}
@Override
public void run() {
while (true) {
synchronized (LOCK) {
// 判断是否轮到当前线程执行
while (current % threadCount != threadNo) {
if (current > maxInt) {
break;
}
try {
// 如果不是,则当前线程进入wait
LOCK.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
// 最大值跳出循环
if (current > maxInt) {
break;
}
System.out.println("thread" + threadNo + " : " + current);
current++;
// 唤醒其他wai韩雯雯,皮蛋豆腐的做法,世界地图t线程
LOCK.notifyAll();
}
}
}
public static void main(String[] args) {
int th小樱本子readCoun排名第一的铜嘴叫声t = 3;
int max 胡彦斌怒怼狗仔= 100;
for (int i = 0; i < threadCount; i++) {
new Thread(new 老司机1(i,天天射天天操 threadCount, max)).start();
}
}
}

核心方法在run里面,可以看见和我们交替打印奇偶数原理差不多,这里将我们的notify改成了notifyAll,这里要注意一下很多人会将notifyAll理解成其他wait的线程全部都会执行,其实是错误的。这里只会将wait的线程解除当前wait状态,也叫作唤醒,由于我们这里用同步锁synchronized块包山东的响马完整顺口溜裹住,那么唤醒的线程会做会抢夺同步锁。

这个老司机的代码的确能跑通,但是有一个问题是什么呢?当我们线程数很大的时候,由于我们不确定唤醒的线程到底是否是下一个要执行的就有可能会出现抢到了锁但不该自己执行,然后又进入wait的情况,比如现在有100个线程,现在是第一个线程在执行,他执行完之后需要第二个线程执行,但是第100个线程抢到了,发现不是自己然后又进入wait,然后第99个线程抢到了,发现不是自己然后又进入wait,然后第98,97...锥体卷板机直到第3个线程都抢到了,最后才到第二个线程抢到同步锁,这里就会白白的多执行很多过程,虽然最后能完成目标。

还有其他老司机用lock/condition也实现了这样的功能,还有老司机用比较新颖的方法比如队列去做,当然这里就不多提了,大致的原理都是基于上面的,这里我说一下我的做法,在Java的多线程中提供了一些常用的同血洒海神庙步器,在这个场景下比较适合于使用Semaphore,也就是信号量,我们上一个线程持有下一个线程的信号量,通过一个信号量数组将全部关联起来,代码如下:

st蒋梦佳atic int result = 0;
public static void main(淫心String[] args) throws InterruptedException {
int N = 3;
Thread[] threads = new Thread[N];
final Semaphore[] syncObjects = new Semaphore[N];
for (int 霍雨浩hi = 0; i < N; i++) {
syncObjects[i] = new Semaphore(1);
if (i != N-1){
syncObjects[i].acquire();
}
}
for (int i = 0; i < N; i++) {
final Semaphore lastSemphore = i == 0 ? syncObjects[N - 1] : syncObjects[i - 1];
final Sem监督不行届aphore curSemphore = syncObjects[i];
final int index = i;
threads[i] = new Thread(new Runnable() {
public void run() {
try {
while (true) {
lastSemphore.acquire();
System.out.println("thread" + index +巫正刚 ": " + result++);
if (result > 100){
余爱绕梁System.exit(0);
}
curSemphore.release();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
threads[i].start();
}
}

通过这种方式,我们就不会有白白唤醒的线程,每一个线程都按照我们所约定的顺序去执行,这其实也是面试官所需要考的地方,让每个线程的执行都能再你手中得到控制,这也可以验证你多线程知识是否牢固。

关注我:私信回复“555”获取往期Java高级架构资料、源码、笔记、视频Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术往期架构视频

文章版权及转载声明:

作者:admin本文地址:http://www.evolution-m.com/articles/508.html发布于 8个月前 ( 03-25 17:59 )
文章转载或复制请以超链接形式并注明出处移动革命,5G来了,新一代移动互联网时代来了