经典面试题
编写一个程序,开启三个线程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();
}
实现代码如下:
![控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到](http://p2.ttnews.xyz/loading.gif)
![控制多线程打印顺序,你可能只能写出前三种,最后一种可能想不到](http://p2.ttnews.xyz/loading.gif)
测试结果:
实现步骤如下:
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方法如下:
- acquire: 方法阻塞,直到有一个许可证可以获取然后拿走一个租客正
- release: 增加一个许可证,然后释放一个阻塞acquire的方法
下面用生活场景介绍
比如××马路要限制流量,只允许同时有一百辆车在这条路上行驶,其他的都必须
在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶
入××马路,但是如果前一百辆中有5辆车已经离开了××马路,那么后面就允许有5辆车驶入马
路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完
成,看见红灯就表示线程被阻塞,不能执行。
实现代码如下:
结果为:
实现原理:
1、首先让A有一个许可证,B C 默认为0个
2、如果B或者C获取执行权,由于没有许可证,线程执行权会到A手中。
3、A 执行后,由于有许可证,所以代码可以执行下去。执行完成后,增加B的许可证。
4、B执行,执行完后,增加C的许可证,C执行完成后,增加A的许可证,A线程再次执行。
如果你有不同的见解,欢迎评论!
閱讀更多 碼農的一天 的文章