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