控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

经典面试题

编写一个程序,开启三个线程A,B,C , 这三个线程输出分别为 A、B、C,要求,按顺序输出ABC,

循环10次, 分别为 ABCABCABCABCABC......

下面介绍以下四种实现方式


2.1 用synchronized、wait、notifyAll实现

标准的实现模式如下

1、等待方遵循如下原则。

(1) 获取对象的锁。

(2) 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。

(3) 条件满足则执行对应的逻辑。

synchronized(对象){

while(条件不满足){

对象.wait();

}

对应的处理逻辑;

}

2、通知方遵循如下原则。

(1) 获得对象的锁。

(2)改变条件。

(3) 通知所有等待在对象上的线程。

synchronized (对象){

改变条件;

对象.notifyAll();

}

实现代码如下:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

测试结果:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

实现步骤如下:

1、线程定义每个线程执行的次数

2、A B C 三个线程都需要先获取锁,无论谁先获取线程执行的优先权,Index 最初值为1,如果B 或者 C 先拿到执行权,则判断后,都会释放锁。最终会A拿到执行权。

3、A执行后正好对index 取模 等于1,然后执行,唤醒B和C线程去执行

4、B 和 C线程拿到执行权后,判断完成后,最终还是B得到执行

5、依次循环下去

2.2 用 ReentrantLock 和 Condition

ReentrantLock 是可重入锁,支持公平和非公平锁。

Condition 条件变量,对于每一个Lock,可以由任意数量的Condition对象,

因此对于不同的条件谓词,对于同一锁,可以用不同的Condition 对象老控制。

Condition 对象会继承相关的Lock公平性,对于公平的锁,线程会一招FIFO 顺序从await中释放。

标准的写法如下:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

实现代码如下:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

测试结果:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

实现原理 和 2.1 类似。

2.3 用 ReentrantLock 和 多个Condition

Condition 能够更加精细的控制多线程的等待和唤醒,并且对于通过一个锁可以创建多个Condition监视器。

利用不同的Condition对象实现当一个线程结束,唤醒下一个线程。

使用volatile 修饰index, 可以在线程之间保持可见性。

实现代码如下:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

结果:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

实现步骤:

1、首先定义一个index区别每个线程。

2、首先 A,B ,C 三个线程同时抢执行权,A的条件是index == 0,B 的条件是 index == 1,

C的条件是 index == 1.

3、满足条件后,依次进行唤醒。

2.4 用 Semaphore 计数器

Semaphore 是一个计数器信号量,必须由获取它的线程释放,通常用于限制可以访问某些资源。

Semaphore方法如下:

  1. acquire: 方法阻塞,直到有一个许可证可以获取然后拿走一个租客正
  2. release: 增加一个许可证,然后释放一个阻塞acquire的方法

下面用生活场景介绍

比如××马路要限制流量,只允许同时有一百辆车在这条路上行驶,其他的都必须

在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶

入××马路,但是如果前一百辆中有5辆车已经离开了××马路,那么后面就允许有5辆车驶入马

路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完

成,看见红灯就表示线程被阻塞,不能执行。

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

实现代码如下:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到

结果为:

控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到


实现原理:

1、首先让A有一个许可证,B C 默认为0个

2、如果B或者C获取执行权,由于没有许可证,线程执行权会到A手中。

3、A 执行后,由于有许可证,所以代码可以执行下去。执行完成后,增加B的许可证。

4、B执行,执行完后,增加C的许可证,C执行完成后,增加A的许可证,A线程再次执行。

如果你有不同的见解,欢迎评论!


分享到:


相關文章: