问题描述
两个线程分别打印A和B,让他们交替打印出“ABABABABABABABABABAB”这样的结果
交替打印是面试中常见的手写代码题,旨在考察对多线程协调工作的理解,有多种实现方法
一般首先想到的是两线程交替阻塞和互相唤醒,使用synchronized、LockSupport、阻塞队列都可以实现
其次可以使用volatile配合轮询来实现非阻塞的模式
方法一:synchronized
public class Solution {
public static void main(String[] args) {
Object lock = new Object();
Thread threadA = new Thread(() -> {
for (int i = 0; i < 10; i++) {
synchronized (lock) {
System.out.println("A");
lock.notify();
try {
if (i < 9) { //最后一次不再wait,让程序可以正常退出
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 10; i++) {
synchronized (lock) {
System.out.println("B");
lock.notify();
try {
if (i < 9) {
lock.wait(); //最后一次不再wait,让程序可以正常退出
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
threadA.start();
try {
Thread.sleep(1000); //保证先打印A
} catch (InterruptedException e) {
e.printStackTrace();
}
threadB.start();
}
}
方法二:LockSupport
import java.util.concurrent.locks.LockSupport;
public class Solution {
private static Thread threadA = null;
private static Thread threadB = null;
public static void main(String[] args) {
threadA = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("A");
LockSupport.unpark(threadB);
if (i < 9) { //最后一次不再park,让程序可以正常退出
LockSupport.park();
}
}
});
threadB = new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("B");
LockSupport.unpark(threadA);
if (i < 9) {
LockSupport.park(); //最后一次不再park,让程序可以正常退出
}
}
});
threadA.start();
try {
Thread.sleep(1000); //保证先打印A
} catch (InterruptedException e) {
e.printStackTrace();
}
threadB.start();
}
}
方法三:阻塞队列
import java.util.concurrent.SynchronousQueue;
public class Solution {
public static void main(String[] args) {
SynchronousQueue<Integer> queue = new SynchronousQueue<>(true); //要用公平模式
Thread threadA = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A");
try {
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("B");
try {
if (i < 9) {
queue.put(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
threadA.start();
try {
Thread.sleep(1000); //保证先A后B的阻塞顺序
} catch (InterruptedException e) {
e.printStackTrace();
}
threadB.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
queue.put(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
方法四:非阻塞模式
public class Solution {
private static volatile char c = 'B'; //使用volatile保证c的可见性
public static void main(String[] args) {
Thread threadA = new Thread(() -> {
for (int i = 0; i < 10; i++) {
while (c != 'B') {
}
System.out.println("A");
c = 'A';
}
});
Thread threadB = new Thread(() -> {
for (int i = 0; i < 10; i++) {
while (c != 'A') {
}
System.out.println("B");
c = 'B';
}
});
threadA.start();
threadB.start();
}
}