實現線程交替打印的幾種方式


線程交替打印的幾種實現方式

  • 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. 理解原理才能寫出對的代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM