先上代码:
public class Printer {
private static final Object lock = new Object();
private static int flg = 1;
private static void start() {
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
for (int i = 1; i <= 26; i++) {
if (flg != 1) {
lock.wait();
}
System.out.print(i);
flg = 2;
lock.notify();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
Thread t2 = new Thread(() -> {
synchronized (lock) {
try {
for (char c = 'a'; c <= 'z'; c++) {
if (flg != 2) {
lock.wait();
}
System.out.print(c);
flg = 1;
lock.notify();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
t2.start();
}
public static void main(String[] args) {
start();
}
}
可以先参考: 多线程交替输出abc100次(wait/notify)-CSDN博客文章浏览阅读72次,点赞2次,收藏3次。那么我们接下来就需要实现Runnable接口了,使用Lambda表达式,首先不考虑计数,我们可以先设为无限循环while(true),然后抢锁,抢到之后,如果发现flag不对,就调wait释放锁,此线程就阻塞在wait那里,直到下次它再被唤醒,才会进入下一轮循环继续抢对象锁。设为while(true)是因为循环是不断重试的,有可能抢到锁但本轮并不应该是它输出,所以用了无限循环,这样也会一直交替打印下去,那我们怎么控制器打印次数呢?为此我引入了计数器,打完c之后加一,最后计数器的值小于一个固定值即可!https://blog.csdn.net/m0_60424152/article/details/136637002?spm=1001.2014.3001.5502 下面我讲讲和本题和链接题的异同之处,这次的题目同样需要标识位1和2。但是本题中for循环一定要放在内侧了,因为只需要打印1遍。我来描述下过程吧,我们抢到对象锁之后进入for循环,如果标识位正确,我们输出并切换标识位,之后唤醒等待的线程抢锁,而本线程则由于标识位不符,调用wait方法进入wait状态并释放锁,那另一个线程就一定可以抢到锁啦!
调用wait后本线程一直在wait处“休息”,当其被唤醒之后,如果抢到锁会继续向下执行。底层原理浅显来说大致如下:操作系统中的monitor管程有几个指针,有一个指针指向抢到锁的线程,一个指针指向wait状态的线程队列,还有一个指向被阻塞住在抢锁的线程队列。我们调用wait后,抢到锁指针指向的线程会加入wait对应指针指向的队列进入wait状态,当期被notify后会进入抢锁队列抢锁,抢到锁之后的表现就是会从wait代码之后的位置开始执行!