实现线程交替打印的几种方式

线程交替打印的几种实现方式

  • synchronized提供的wait、notify
  • LockSupport的park、unpark
  • ReentrantLock和condition
  • 基于cas机制实现线程交替打印
  • TransferQueue实现

synchronized提供的wait、notify

/**
 * @author yanyapan
 */
public class WaitNotifyToPrint {
    public static void main(String[] args) {
        final Object object = new Object();
        char[] a1 = "1234567".toCharArray();
        char[] a2 = "ABCDEFG".toCharArray();

        new Thread(() -> {
            synchronized (object){
                for(char c : a1){
                    System.out.print(c);
                    try{
                        object.notify();
                        object.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                object.notify();//避免有线程未被唤醒
            }
        },"t1").start();

        new Thread(() -> {
            synchronized (object){
                for(char c : a2){
                    System.out.print(c);
                    try{
                        object.notify();
                        object.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                object.notify();//避免有线程未被唤醒
            }
        },"t2").start();
    }
}

LockSupport的park、unpark

/**
 * @author yanyapan
 */
public class LockSupportToPrint {

    private static Thread t1;

    private static Thread t2;

    public static void main(String[] args) {
        char[] a1 = "1234567".toCharArray();
        char[] a2 = "ABCDEFG".toCharArray();

        t1 = new Thread(() -> {
            for(char c : a1){
                System.out.print(c);
                LockSupport.unpark(t2);//释放t2线程 设置锁标志位
                LockSupport.park();//阻塞当前线程
            }
        },"t1");

        t2 = new Thread(() -> {
            for(char c : a2){
                LockSupport.park();//阻塞当前线程
                System.out.print(c);
                LockSupport.unpark(t1);//释放t1线程
            }
        },"t2");

        t1.start();
        t2.start();
    }

}

ReentrantLock和condition

/**
 * @author yanyapan
 */
public class LockConditionToPrint {
    public static void main(String[] args) {
        char[] a1 = "1234567".toCharArray();
        char[] a2 = "ABCDEFG".toCharArray();
        Lock lock = new ReentrantLock();//锁
        Condition t1 = lock.newCondition();//t1队列
        Condition t2 = lock.newCondition();//t2队列

        new Thread(() ->{
            try{
                lock.lock();
                for(char c : a1){
                    System.out.print(c);
                    t2.signal();//唤醒t2队列中等待的线程
                    t1.await();//进入t1队列自旋等待
                }
                t1.signal();//避免有线程未被唤醒
                t2.signal();//避免有线程未被唤醒
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t1").start();

        new Thread(() ->{
            try{
                lock.lock();
                for(char c : a2){
                    System.out.print(c);
                    t1.signal();//唤醒t1队列中等待的线程
                    t2.await();//进入t2队列自旋等待
                }
                t1.signal();//避免有线程未被唤醒
                t2.signal();//避免有线程未被唤醒
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        },"t2").start();
    }
}

基于cas机制实现线程交替打印

/**
 * @author yanyapan
 */
public class CasToPrint {

    enum ReadyToRun{
        T1,T2
    }
    private static volatile ReadyToRun readyToRun = ReadyToRun.T1;

    public static void main(String[] args) {
        char[] a1 = "1234567".toCharArray();
        char[] a2 = "ABCDEFG".toCharArray();

        new Thread(() ->{
            for(char c : a1){
                while (readyToRun != ReadyToRun.T1){}//cas自旋
                System.out.print(c);
                readyToRun = ReadyToRun.T2;//线程可见性
            }
        },"t1").start();

        new Thread(() ->{
            for(char c : a2){
                while (readyToRun != ReadyToRun.T2){}//cas自旋
                System.out.print(c);
                readyToRun = ReadyToRun.T1;//线程可见性
            }
        },"t2").start();
    }
}

TransferQueue实现

/**
 * @author yanyapan
 */
public class TransferQueueToPrint {
    public static void main(String[] args) {
        char[] a1 = "1234567".toCharArray();
        char[] a2 = "ABCDEFG".toCharArray();
        TransferQueue<Character> queue = new LinkedTransferQueue<>();
        new Thread(() ->{
            try{
                for(char c : a1){
                    System.out.print(queue.take());
                    queue.transfer(c);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"t1").start();

        new Thread(() ->{
            try{
                for(char c : a2){
                    queue.transfer(c);
                    System.out.print(queue.take());
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        },"t2").start();
    }
}

总结:

  1. 需要对jdk底层有深刻的理解,如aqs、synchronized的锁升级过程、cas机制(jdk中atomic包中大量使用)
  2. 对jdk中提供的并发数据结构学习掌握
  3. 理解原理才能写出对的代码
posted @ 2020-05-19 09:43  yanyapan  阅读(2142)  评论(0编辑  收藏  举报