问题描述
有两个线程,一个线程只打印奇数,一个线程只打印偶数,而且要按照顺序打印,就是说要按照这样的方式打印:
偶线程:0
奇线程:1
偶线程:2
奇线程:3
…
方案一:使用synchronized关键字
要点:
- 创建两个线程,一个线程处理偶数,一个线程处理奇数
- 两个线程之间通过synchronized进行同步,保证count++每次只有一个线程进行操作
- 为什么两个线程能交替执行,这里很巧的是
,实际上两个线程都是在不停的尝试(while循环)进入synchronized代码块,如果满足相对应的条件(偶数或是奇数)就打印输出。count从0123自增过程就是一个奇偶数交替的过程
public class WaitNotifyPrintOddEvenSyn {
private static int count;
private static final Object lock = new Object();
/**
* 新建2个线程,第一个只处理偶数,第二个只处理奇数(用位运算);用synchronized来通信
*/
public static void main(String[] args) {
new Thread(() -> {
while (count < 100) {
synchronized (lock) {
if ((count & 1) == 0) {
System.out.println(Thread.currentThread().getName() + ":" + count++);
}
}
}
}, "偶线程").start();
new Thread(() -> {
while (count < 100) {
synchronized (lock) {
if ((count & 1) == 1) {
System.out.println(Thread.currentThread().getName() + ":" + count++);
}
}
}
}, "奇线程").start();
}
}
方案二:使用wait/notify关键字(推荐)
要点:
- 这个相对于上面那个好理解很多,直接走流程,偶数线程拿到锁打印输出同时count++,然后进行休眠,因为
,奇数线程就可以进来了,进来后打印输出,同时notify唤醒偶数线程继续下一轮,奇数线程往下执行wait方法休眠,就这样,偶数线程唤醒奇数线程,奇数线程唤醒偶数线程,直到满足count<100条件后,线程不再休眠,直接退出程序。wait()方法的特性,休眠的同时会释放monitor锁
- 这个要点一个在于
,一个在于wait()方法的特性,休眠后会释放锁。wait/notify的等待唤醒机制
- 这种方式和上面那种方式不同点在于,这种方式是
,而上面那个是线程不断重试的机制(一直while重试,直到满足条件就打印),很明显这种方式优于上面那种!被动唤醒的机制
public class WaitNotifyPrintOddEveWait {
private static int count = 0;
private static final Object lock = new Object();
public static void main(String[] args) {
new Thread(new TurningRunner(), "偶线程").start();
new Thread(new TurningRunner(), "奇线程").start();
}
/**
* 1. 拿到锁,立刻打印
* 2. 打印完,唤醒其他线程,自己就休眠
*/
static class TurningRunner implements Runnable {
@Override
public void run() {
while (count < 100) {
synchronized (lock) {
//拿到锁就打印
System.out.println(Thread.currentThread().getName() + ":" + count++);
lock.notify();
if (count < 100) {
try {
//如果任务还没结束,就让出当前的锁,并休眠
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
方案三:可以使用ReentrantLock,设置为公平锁,即等待时间越长的线程先执行
笔记来源:慕课网悟空老师视频《Java并发核心知识体系精讲》