问题
有两个线程,一个打印'A'、 'B' 、 'C', 另一个打印 '1'、 '2' 、 '3',怎样让他们打印"1A2B3C"?
1. 使用条件队列
我们可以先创建一个锁对象,使用该锁守护两个线程中的代码块,通过调用锁对象的 wait() 和 notify/notifyAll()来阻塞或唤醒两个线程的执行。
class Solution1 {
private final Object lock = new Object();
public static void main(String[] args) {
new Solution1().print();
}
private void print() {
new Thread(() -> {
int i = 0;
while (true) {
synchronized (lock) {
try {
System.out.print(i + 1);
lock.notify();
if (i++ == 2) return;
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(() -> {
int i = 0;
while (true) {
synchronized (lock) {
try {
System.out.print((char) ('A' + i));
lock.notify();
if (i++ == 2) return;
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
2. 使用显式的Condition对象
Condition 是一种广义的内置条件队列,所以该方法与方法1中的实现方式没有本质的区别。
class Solution2 {
private Lock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
public static void main(String[] args) {
new Solution2().print();
}
private void print() {
new Thread(() -> {
int i = 0;
while (true) {
lock.lock();
try {
System.out.print(i + 1);
c2.signal();
if (i++ == 2) return;
c1.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
new Thread(() -> {
int i = 0;
while (true) {
try {
if (i == 0) {
TimeUnit.MILLISECONDS.sleep(10);
}
lock.lock();
System.out.print((char) ('A' + i));
c1.signal();
if (i++ == 2) return;
c2.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}).start();
}
}
3. 使用信号量
分别定义对应于两个线程的两个信号量 (Semaphore)对象,使用两个信号量的 acquire()和 release() 方法控制线程的阻塞和唤醒。
class Solution3 {
private Semaphore s1 = new Semaphore(1);
private Semaphore s2 = new Semaphore(0);
public static void main(String[] args) {
new Solution3().print();
}
private void print() {
new Thread(() -> {
int i = 0;
while (true) {
try {
s1.acquire();
System.out.print(i + 1);
s2.release();
if (i++ == 2) return;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(() -> {
int i = 0;
while (true) {
try {
s2.acquire();
System.out.print((char) ('A' + i));
s1.release();
if (i++ == 2) return;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}