第一种方法,使用 {Object#wait()},{Object#notify()}的方式
public class OldEvenTest {
public static void main(String[] args) {
//监视器对象
Object monitor = new Object();
new Thread(new EvenPrintTask(monitor), "偶数").start();
new Thread(new OldPrintTask(monitor), "奇数").start();
}
static class OldPrintTask implements Runnable {
private Object monitor;
//奇数线程从1开始打印
private int value = 1;
public OldPrintTask(Object monitor) {
this.monitor = monitor;
}
@Override
public void run() {
while (value <100) {
synchronized (monitor) {
System.out.println(Thread.currentThread().getName() + ":" + value);
value += 2;
monitor.notify();
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class EvenPrintTask implements Runnable {
private Object monitor;
//偶数对象
private int value = 0;
public EvenPrintTask(Object monitor) {
this.monitor = monitor;
}
@Override
public void run() {
while (value <= 100) {
synchronized (monitor) {
System.out.println(Thread.currentThread().getName() + ":" + value);
value += 2;
monitor.notify();
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
偶数线程的run方法
@Override
public void run() {
while (value <= 100) {
synchronized (monitor) {
System.out.println(Thread.currentThread().getName() + ":" + value);
value += 2;
monitor.notify();
try {
//打印出100以后,还是会继续等待直到其他线程唤醒当前线程。
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这种方式存在一个问题,就是偶数线程最终打印出100以后,还是会继续等待。我们修改一下偶数线程的run方法,当打印出100以后,就不再调用monitor.wait()方法。如下所示:
@Override
public void run() {
while (value <= 100) {
synchronized (monitor) {
System.out.println(Thread.currentThread().getName() + ":" + value);
value += 2;
monitor.notify();
try {
//打印出100以后,不再等待,直接退出
if (value <= 100) {
monitor.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
第二种的方法,使用Lock+Condition的方式
private static int count = 0;
private static void method2() {
Lock lock = new ReentrantLock();
Condition evenCondition = lock.newCondition();
Condition oldCondition = lock.newCondition();
//偶数线程
new Thread(new Runnable() {
@Override
public void run() {
while (count <= 100) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + ":" + count);
count++;
//唤醒奇数线程
oldCondition.signal();
//打印出100后,就不再等待
if (count <= 100) {
evenCondition.await();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}, "偶数").start();
//奇数线程
new Thread(new Runnable() {
@Override
public void run() {
while (count <= 100) {
try {
lock.lock();
System.out.println(Thread.currentThread().getName() + ":" + count);
count++;
//唤醒偶数线程
evenCondition.signal();
oldCondition.await();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}, "奇数").start();
}
第三种方法,使用并发包中的AtomicInteger和volatile修饰符组合
//保证flag的线程可见性
private static volatile Boolean flag = true;
private static AtomicInteger num = new AtomicInteger();
private static final Integer TOTAL = 100;
private static void method3() {
Thread jsThread = new Thread(new Runnable() {
@Override
public void run() {
while (num.get() <= TOTAL - 1) {
if (!flag) {
System.out.println(Thread.currentThread().getName() + ": "
+ num.getAndIncrement());
flag = true;
}
}
}
});
jsThread.setName("奇数线程");
Thread osThread = new Thread(new Runnable() {
@Override
public void run() {
while (num.get() <= TOTAL) {
if (flag) {
System.out.println(Thread.currentThread().getName() + ":"
+ num.getAndIncrement());
flag = false;
}
}
}
});
osThread.setName("偶数线程");
osThread.start();
jsThread.start();
}
参看链接
5种操作带你玩转【交替打印奇偶数】
注意该链接中的使用ReentrantLock与Condition这种方式有问题,唤醒其他线程的操作signal应该在当前线程等待await之前。可以自己测试一下。