Problem description
Two threads print A and B, and have them alternately print something like “ababababababababab”
Alternate printing is a common handwritten code question in the interview, which aims to test the understanding of multi-threaded coordination work. There are many ways to achieve it
The first thing that usually comes to mind is that two threads block alternately and wake up each other, which can be achieved using synchronized, LockSupport, and blocking queues
Second, volatile can be used in conjunction with polling to implement a non-blocking pattern
Method 1: 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 for the last time so that the program can exit normallylock.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 for the last time so that the program can exit normally}}catch(InterruptedException e) { e.printStackTrace(); }}}}); threadA.start();try {
Thread.sleep(1000); // Make sure to print A first
} catch(InterruptedException e) { e.printStackTrace(); } threadB.start(); }}Copy the code
Method 2: 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) { // Stop park for the last time so that the program can exit normallyLockSupport.park(); }}}); threadB =new Thread(() -> {
for (int i = 0; i < 10; i++) {
System.out.println("B");
LockSupport.unpark(threadA);
if (i < 9) {
LockSupport.park(); // Stop park for the last time so that the program can exit normally}}}); threadA.start();try {
Thread.sleep(1000); // Make sure to print A first
} catch(InterruptedException e) { e.printStackTrace(); } threadB.start(); }}Copy the code
Method three: block the queue
import java.util.concurrent.SynchronousQueue;
public class Solution {
public static void main(String[] args) {
SynchronousQueue<Integer> queue = new SynchronousQueue<>(true); // Use fair mode
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); // ensure that A is blocked before 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(); }}}Copy the code
Method 4: Non-blocking mode
public class Solution {
private static volatile char c = 'B'; // Use volatile to make c visible
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(); }}Copy the code