今天去某公司面试,其中有一道手写3个线程交替输出打印1-100的编程题。于是乎本码农不惧挑战,开工手写,写的过程中总觉得少了点什么,有些不对。
做完笔试题后,面试管匆匆忙忙地赶来,电脑上的界面还停留在 IDEA 的界面。我和面试官寒暄几句后,就开始了具体的面试流程。
不知道是不是去的太早了,打扰到了面试官调试代码。还是编程题因为纯手写,被找出了瑕疵。最终,今天的面试反馈结果没过。
废话不多说,上代码。
1. 利用synchronize 关键字、 object.wait 、 object.notifyAll 来实现
/**
*
* 〈3个线程交替打印1-100〉
* @author cqwshzj
* @create 2021/4/13
* @since 1.0.0
*/
public class TestMain {
public static void main(String[] args) {
MyCounter counter = new MyCounter();
final int limit = 110;
int divisorNum = 3;
Runnable worker0 = new PrintWorker( counter , limit, divisorNum, 0);
Runnable worker1 = new PrintWorker( counter , limit, divisorNum, 1);
Runnable worker2 = new PrintWorker( counter , limit, divisorNum, 2);
final Thread thread0 = new Thread( worker0 );
final Thread thread1 = new Thread( worker1 );
final Thread thread2 = new Thread( worker2 );
thread0.setName("Print0Worker");
thread1.setName("Print1Worker");
thread2.setName("Print2Worker");
thread0.start();
thread1.start();
thread2.start();
}
}
/** 计数器 */
class MyCounter {
public volatile int num =1;
}
/** 打印对应余数的线程 */
class PrintWorker implements Runnable{
/** 计数器 */
private MyCounter myCounter;
/** 总器 */
private int limit = 9;
/** 除数 */
private int remainderNum;
/** 余数 */
private int divisorNum ;
/**
*
* @param myCounter 计数器
* @param limit 总器
* @param divisorNum 除数
* @param remainderNum 余数
*/
public PrintWorker(MyCounter myCounter, int limit, int divisorNum, int remainderNum) {
this.myCounter = myCounter;
this.limit = limit;
this.divisorNum = divisorNum;
this.remainderNum = remainderNum;
}
@Override
public void run() {
while ( myCounter.num <= limit ){
synchronized ( myCounter ){
if ( myCounter.num % divisorNum == remainderNum ){
System.out.println( Thread.currentThread().getName()+" ---> myCounter.num = " + myCounter.num);
myCounter.num ++;
myCounter.notifyAll();
}else{
try {
myCounter.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
运行结果如下
Connected to the target VM, address: '127.0.0.1:58098', transport: 'socket'
Print1Worker ---> myCounter.num = 1
Print2Worker ---> myCounter.num = 2
Print0Worker ---> myCounter.num = 3
Print1Worker ---> myCounter.num = 4
Print2Worker ---> myCounter.num = 5
Print0Worker ---> myCounter.num = 6
Print1Worker ---> myCounter.num = 7
Print2Worker ---> myCounter.num = 8
Print0Worker ---> myCounter.num = 9
Print1Worker ---> myCounter.num = 10
Print2Worker ---> myCounter.num = 11
Print0Worker ---> myCounter.num = 12
Print1Worker ---> myCounter.num = 13
Print2Worker ---> myCounter.num = 14
Print0Worker ---> myCounter.num = 15
Print1Worker ---> myCounter.num = 16
Print2Worker ---> myCounter.num = 17
Print0Worker ---> myCounter.num = 18
Print1Worker ---> myCounter.num = 19
Print2Worker ---> myCounter.num = 20
Print0Worker ---> myCounter.num = 21
Print1Worker ---> myCounter.num = 22
Print2Worker ---> myCounter.num = 23
Print0Worker ---> myCounter.num = 24
Print1Worker ---> myCounter.num = 25
Print2Worker ---> myCounter.num = 26
Print0Worker ---> myCounter.num = 27
Print1Worker ---> myCounter.num = 28
Print2Worker ---> myCounter.num = 29
Print0Worker ---> myCounter.num = 30
Print1Worker ---> myCounter.num = 31
Print2Worker ---> myCounter.num = 32
Print0Worker ---> myCounter.num = 33
Print1Worker ---> myCounter.num = 34
Print2Worker ---> myCounter.num = 35
Print0Worker ---> myCounter.num = 36
Print1Worker ---> myCounter.num = 37
Print2Worker ---> myCounter.num = 38
Print0Worker ---> myCounter.num = 39
Print1Worker ---> myCounter.num = 40
Print2Worker ---> myCounter.num = 41
Print0Worker ---> myCounter.num = 42
Print1Worker ---> myCounter.num = 43
Print2Worker ---> myCounter.num = 44
Print0Worker ---> myCounter.num = 45
Print1Worker ---> myCounter.num = 46
Print2Worker ---> myCounter.num = 47
Print0Worker ---> myCounter.num = 48
Print1Worker ---> myCounter.num = 49
Print2Worker ---> myCounter.num = 50
Print0Worker ---> myCounter.num = 51
Print1Worker ---> myCounter.num = 52
Print2Worker ---> myCounter.num = 53
Print0Worker ---> myCounter.num = 54
Print1Worker ---> myCounter.num = 55
Print2Worker ---> myCounter.num = 56
Print0Worker ---> myCounter.num = 57
Print1Worker ---> myCounter.num = 58
Print2Worker ---> myCounter.num = 59
Print0Worker ---> myCounter.num = 60
Print1Worker ---> myCounter.num = 61
Print2Worker ---> myCounter.num = 62
Print0Worker ---> myCounter.num = 63
Print1Worker ---> myCounter.num = 64
Print2Worker ---> myCounter.num = 65
Print0Worker ---> myCounter.num = 66
Print1Worker ---> myCounter.num = 67
Print2Worker ---> myCounter.num = 68
Print0Worker ---> myCounter.num = 69
Print1Worker ---> myCounter.num = 70
Print2Worker ---> myCounter.num = 71
Print0Worker ---> myCounter.num = 72
Print1Worker ---> myCounter.num = 73
Print2Worker ---> myCounter.num = 74
Print0Worker ---> myCounter.num = 75
Print1Worker ---> myCounter.num = 76
Print2Worker ---> myCounter.num = 77
Print0Worker ---> myCounter.num = 78
Print1Worker ---> myCounter.num = 79
Print2Worker ---> myCounter.num = 80
Print0Worker ---> myCounter.num = 81
Print1Worker ---> myCounter.num = 82
Print2Worker ---> myCounter.num = 83
Print0Worker ---> myCounter.num = 84
Print1Worker ---> myCounter.num = 85
Print2Worker ---> myCounter.num = 86
Print0Worker ---> myCounter.num = 87
Print1Worker ---> myCounter.num = 88
Print2Worker ---> myCounter.num = 89
Print0Worker ---> myCounter.num = 90
Print1Worker ---> myCounter.num = 91
Print2Worker ---> myCounter.num = 92
Print0Worker ---> myCounter.num = 93
Print1Worker ---> myCounter.num = 94
Print2Worker ---> myCounter.num = 95
Print0Worker ---> myCounter.num = 96
Print1Worker ---> myCounter.num = 97
Print2Worker ---> myCounter.num = 98
Print0Worker ---> myCounter.num = 99
Print1Worker ---> myCounter.num = 100
Print2Worker ---> myCounter.num = 101
Print0Worker ---> myCounter.num = 102
Print1Worker ---> myCounter.num = 103
Print2Worker ---> myCounter.num = 104
Print0Worker ---> myCounter.num = 105
Print1Worker ---> myCounter.num = 106
Print2Worker ---> myCounter.num = 107
Print0Worker ---> myCounter.num = 108
Print1Worker ---> myCounter.num = 109
Print2Worker ---> myCounter.num = 110
Disconnected from the target VM, address: '127.0.0.1:58098', transport: 'socket'
Process finished with exit code 0
2. 利用 ReentrantLock 和 Condition 来实现
public class PrintReentrantLockConditionTest {
public static void main(String[] args) {
final ReentrantLock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
final int startNum = 1;
MyCounter counter = new MyCounter(startNum);
final int endNum = 110;
int divisorNum = 3;
Runnable worker0 = new ReentrantLockPrintWorker( counter , endNum, divisorNum, 0, lock, condition);
Runnable worker1 = new ReentrantLockPrintWorker( counter , endNum, divisorNum, 1, lock, condition);
Runnable worker2 = new ReentrantLockPrintWorker( counter , endNum, divisorNum, 2, lock, condition);
final Thread thread0 = new Thread( worker0 );
final Thread thread1 = new Thread( worker1 );
final Thread thread2 = new Thread( worker2 );
thread0.setName("Print0Worker");
thread1.setName("Print1Worker");
thread2.setName("Print2Worker");
thread0.start();
thread1.start();
thread2.start();
}
}
/** 计数器 */
public class MyCounter {
public volatile int num ;
public MyCounter(int num) {
this.num = num;
}
}
/** 打印余数的线程 */
class ReentrantLockPrintWorker implements Runnable{
/** 计数器 */
private MyCounter myCounter;
/** 总器 */
private int endNum = 9;
/** 除数 */
private int remainderNum;
/** 余数 */
private int divisorNum ;
//---------
private ReentrantLock lock ;
private Condition condition;
public ReentrantLockPrintWorker(MyCounter myCounter,
int endNum,
int divisorNum,
int remainderNum,
ReentrantLock lock,
Condition condition) {
this.myCounter = myCounter;
this.endNum = endNum;
this.remainderNum = remainderNum;
this.divisorNum = divisorNum;
this.lock = lock;
this.condition = condition;
}
//---------
@Override
public void run() {
while ( myCounter.num <= endNum ){
try {
lock.lock();
if ( myCounter.num % divisorNum == remainderNum ){
System.out.println(Thread.currentThread().getName()+" --> myCounter.num = " + myCounter.num);
myCounter.num++;
condition.signalAll();
}else{
condition.await();
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
}
运行效果
Print1Worker --> myCounter.num = 1
Print2Worker --> myCounter.num = 2
Print0Worker --> myCounter.num = 3
Print1Worker --> myCounter.num = 4
Print2Worker --> myCounter.num = 5
Print0Worker --> myCounter.num = 6
Print1Worker --> myCounter.num = 7
Print2Worker --> myCounter.num = 8
Print0Worker --> myCounter.num = 9
Print1Worker --> myCounter.num = 10
Print2Worker --> myCounter.num = 11
Print0Worker --> myCounter.num = 12
Print1Worker --> myCounter.num = 13
Print2Worker --> myCounter.num = 14
Print0Worker --> myCounter.num = 15
Print1Worker --> myCounter.num = 16
Print2Worker --> myCounter.num = 17
Print0Worker --> myCounter.num = 18
Print1Worker --> myCounter.num = 19
Print2Worker --> myCounter.num = 20
Print0Worker --> myCounter.num = 21
Print1Worker --> myCounter.num = 22
Print2Worker --> myCounter.num = 23
Print0Worker --> myCounter.num = 24
Print1Worker --> myCounter.num = 25
Print2Worker --> myCounter.num = 26
Print0Worker --> myCounter.num = 27
Print1Worker --> myCounter.num = 28
Print2Worker --> myCounter.num = 29
Print0Worker --> myCounter.num = 30
Print1Worker --> myCounter.num = 31
Print2Worker --> myCounter.num = 32
Print0Worker --> myCounter.num = 33
Print1Worker --> myCounter.num = 34
Print2Worker --> myCounter.num = 35
Print0Worker --> myCounter.num = 36
Print1Worker --> myCounter.num = 37
Print2Worker --> myCounter.num = 38
Print0Worker --> myCounter.num = 39
Print1Worker --> myCounter.num = 40
Print2Worker --> myCounter.num = 41
Print0Worker --> myCounter.num = 42
Print1Worker --> myCounter.num = 43
Print2Worker --> myCounter.num = 44
Print0Worker --> myCounter.num = 45
Print1Worker --> myCounter.num = 46
Print2Worker --> myCounter.num = 47
Print0Worker --> myCounter.num = 48
Print1Worker --> myCounter.num = 49
Print2Worker --> myCounter.num = 50
Print0Worker --> myCounter.num = 51
Print1Worker --> myCounter.num = 52
Print2Worker --> myCounter.num = 53
Print0Worker --> myCounter.num = 54
Print1Worker --> myCounter.num = 55
Print2Worker --> myCounter.num = 56
Print0Worker --> myCounter.num = 57
Print1Worker --> myCounter.num = 58
Print2Worker --> myCounter.num = 59
Print0Worker --> myCounter.num = 60
Print1Worker --> myCounter.num = 61
Print2Worker --> myCounter.num = 62
Print0Worker --> myCounter.num = 63
Print1Worker --> myCounter.num = 64
Print2Worker --> myCounter.num = 65
Print0Worker --> myCounter.num = 66
Print1Worker --> myCounter.num = 67
Print2Worker --> myCounter.num = 68
Print0Worker --> myCounter.num = 69
Print1Worker --> myCounter.num = 70
Print2Worker --> myCounter.num = 71
Print0Worker --> myCounter.num = 72
Print1Worker --> myCounter.num = 73
Print2Worker --> myCounter.num = 74
Print0Worker --> myCounter.num = 75
Print1Worker --> myCounter.num = 76
Print2Worker --> myCounter.num = 77
Print0Worker --> myCounter.num = 78
Print1Worker --> myCounter.num = 79
Print2Worker --> myCounter.num = 80
Print0Worker --> myCounter.num = 81
Print1Worker --> myCounter.num = 82
Print2Worker --> myCounter.num = 83
Print0Worker --> myCounter.num = 84
Print1Worker --> myCounter.num = 85
Print2Worker --> myCounter.num = 86
Print0Worker --> myCounter.num = 87
Print1Worker --> myCounter.num = 88
Print2Worker --> myCounter.num = 89
Print0Worker --> myCounter.num = 90
Print1Worker --> myCounter.num = 91
Print2Worker --> myCounter.num = 92
Print0Worker --> myCounter.num = 93
Print1Worker --> myCounter.num = 94
Print2Worker --> myCounter.num = 95
Print0Worker --> myCounter.num = 96
Print1Worker --> myCounter.num = 97
Print2Worker --> myCounter.num = 98
Print0Worker --> myCounter.num = 99
Print1Worker --> myCounter.num = 100
Print2Worker --> myCounter.num = 101
Print0Worker --> myCounter.num = 102
Print1Worker --> myCounter.num = 103
Print2Worker --> myCounter.num = 104
Print0Worker --> myCounter.num = 105
Print1Worker --> myCounter.num = 106
Print2Worker --> myCounter.num = 107
Print0Worker --> myCounter.num = 108
Print1Worker --> myCounter.num = 109
Print2Worker --> myCounter.num = 110
Disconnected from the target VM, address: '127.0.0.1:61346', transport: 'socket'
Process finished with exit code 0