经典面试题:两个线程交替打印数字和字符

问题:A和B两个线程,A线程打印数字,B线程打印字符,实现交替打印。例如:a1b2c3…
解决方案
  • 方案一:LockSupport实现
package exercise.map.thread;

import java.util.concurrent.locks.LockSupport;

/**
 * Copyright (c) 2020.
 * Email: [email protected]
 *
 * @author lyg  2020/3/18 上午11:04
 **/

public class ThreadPrint_LockSupport {
    private static Thread t1, t2;

    public static void main(String[] args) {
        int[] aI = {1, 2, 3, 4, 5, 6, 7};
        char[] aC = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
        t1 = new Thread(() -> {
            for (int i : aI) {
                System.out.print(i);
                LockSupport.unpark(t2);
                LockSupport.park();
            }
            LockSupport.unpark(t2);
        }, "t1");
        t2 = new Thread(() -> {
            for (char ch : aC) {
                LockSupport.park();
                System.out.print(ch);
                LockSupport.unpark(t1);
            }
            LockSupport.unpark(t1);
        }, "t2");
        t1.start();
        t2.start();
    }
}

LockSupport.unpark(t2);唤醒t2线程,为给定的线程提供许可证(如果尚未提供)。 如果线程在park被阻塞,那么它将被解除阻塞。 否则,其下一次拨打park保证不被阻止。 如果给定的线程尚未启动,则此操作无法保证完全没有任何影响。
LockSupport.park();阻塞当前线程,禁止当前线程进行线程调度,除非许可证可用。

  • 方案二:自旋锁
package exercise.map.thread;

/**
 * Copyright (c) 2020.
 * Email: [email protected]
 *
 * @author lyg  2020/3/18 上午11:19
 * description:
 **/

public class ThreadPrint_Spin {
    enum ReadToRun {
        T1, T2
    }

    static volatile ReadToRun readToRun = ReadToRun.T1;

    public static void main(String[] args) {
        int[] aI = {1, 2, 3, 4, 5, 6, 7};
        char[] aC = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
        new Thread(() -> {
            for (int i : aI) {
                //noinspection StatementWithEmptyBody
                while (readToRun != ReadToRun.T1) {
                }///end while
                System.out.print(i);
                readToRun = ReadToRun.T2;
            }end for
        }, "t1").start();

        new Thread(() -> {
            for (char ch : aC) {
                //noinspection StatementWithEmptyBody
                while (readToRun != ReadToRun.T2) {
                }///end while
                System.out.print(ch);
                readToRun = ReadToRun.T1;
            }end for
        }, "t2").start();
    }
}

static volatile ReadToRun readToRun = ReadToRun.T1;静态变量隶属于类,并且使用volatile修饰,保证了线程的可见性,t1线程修改readToRun 变量的值后t2线程可以立即访问到,两个线程根据readToRun 变量值进行交替打印。

  • 方案三:使用wait(),notify()阻塞锁实现
package exercise.map.thread;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * Copyright (c) 2020.
 * Email: [email protected]
 * @author lyg  2020/3/18 上午11:29
 * description:
 **/

public class ThreadPrint_Lock {
    private static volatile AtomicInteger first = new AtomicInteger(0);
    public static void main(String[] args) {
        int[] aI = {1, 2, 3, 4, 5, 6, 7};
        char[] aC = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
        Object lock = new Object();
        new Thread(() -> {
            //noinspection StatementWithEmptyBody
            while (first.get() != 1){}///spin
            first.set(0);
            synchronized (lock){
                for (int i : aI) {
                    System.out.print(i);
                    lock.notify();
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }end for
                lock.notify();
            }
        }, "t1").start();

        new Thread(() -> {
            //noinspection StatementWithEmptyBody
            while (first.get() != 0){;}///spin
            first.set(1);
           synchronized (lock){
               for (char ch : aC) {
                   System.out.print(ch);
                   lock.notify();
                   try {
                       lock.wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }end for
               lock.notify();
           }
        }, "t2").start();
    }
}

当前线程打印一次值后,调用notify()方法唤醒另一个线程,然后再调用wait()方法阻塞当前线程,等待另一个线程来唤醒。

  • 运行结果截图

欢迎关注南阁公众号

南阁子也

你可能感兴趣的:(面试)