成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

多線程交替輸出A1B2C3D4...你怎么實現?

開發 前端
CountDownLatch是Java多線程中的一個同步工具類,它可以讓一個或多個線程等待其他線程完成操作后再繼續執行。

引言

不知道最近有沒有小伙伴去面試,今天了不起回想到了早期去面試遇到的一個多線程面試問題。

面試問題是一個筆試題:

兩個線程依次交替輸出A~Z,1到26,形如A1B2C3D4...

當時的我還很菜,用了原生的線程,借助wait和notify方法實現。

伙伴們你們也可以先暫停,自己思考下用什么方式來實現。

今天了不起和伙伴們一起來基于JDK1.8進行實現方式的探索,請看下文。

1. 使用線程方法

wait()方法會使當前線程釋放鎖,并進入等待狀態,直到以下情況之一發生:

  • 被其他線程調用notify()方法喚醒;
  • 被其他線程調用notifyAll()方法喚醒;
  • 被其他線程中斷。

notify()方法用于喚醒一個正在等待的線程,使其從wait()方法中返回。

結合一個出讓等待的機制,就這樣交替實現。

public class T06_00_sync_wait_notify {
    public static void main(String[] args) {
        final Object o = new Object();

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        new Thread(()->{
            synchronized (o) {
                for(char c : aI) {
                    System.out.print(c);
                    try {
                        o.notify();
                        o.wait(); //讓出鎖
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify(); //必須,否則無法停止程序
            }

        }, "t1").start();

        new Thread(()->{
            synchronized (o) {
                for(char c : aC) {
                    System.out.print(c);
                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify();
            }
        }, "t2").start();
    }
}

運行結果:

圖片圖片

思考:伙伴們,如果我想保證t2在t1之前打印,也就是說保證首先輸出的是A而不是1,這個時候該如何做?

2. 使用CountDownLatch鐵門閂

CountDownLatch是Java多線程中的一個同步工具類,它可以讓一個或多個線程等待其他線程完成操作后再繼續執行。

具體來說,CountDownLatch有兩個主要方法:

  1. await()方法:調用該方法的線程會進入等待狀態,直到計數器的值為0或者被中斷;
  2. countDown()方法:調用該方法會將計數器減1,當計數器的值為0時,會喚醒所有等待的線程。
public class T07_00_sync_wait_notify {

    private static CountDownLatch latch = new CountDownLatch(1);

    public static void main(String[] args) {
        final Object o = new Object();



        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        new Thread(()->{
            try {
                latch.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            synchronized (o) {
                for(char c : aI) {
                    System.out.print(c);
                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                o.notify();
            }
        }, "t1").start();

        new Thread(()->{

            synchronized (o) {
                for(char c : aC) {
                    System.out.print(c);
                    latch.countDown();
                    try {
                        o.notify();
                        o.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                o.notify();
            }
        }, "t2").start();
    }
}

運行結果:

圖片圖片

3. 使用ReentrantLock

我們可以通過ReentrantLock獲取條件鎖,通過它提供的方法來實現。

具體來說,ReentrantLock的Condition接口提供了以下三個方法:

  1. await()方法:當前線程進入等待狀態,并釋放鎖,直到其他線程使用signal()或signalAll()方法喚醒它;
  2. signal()方法:喚醒一個等待在該條件上的線程;
  3. signalAll()方法:喚醒所有等待在該條件上的線程。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T08_00_lock_condition {

    public static void main(String[] args) {

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aI) {
                    System.out.print(c);
                    condition.signal();
                    condition.await();
                }

                condition.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t1").start();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aC) {
                    System.out.print(c);
                    condition.signal();
                    condition.await();
                }

                condition.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t2").start();
    }
}

運行結果:

圖片圖片

Condition本質是鎖資源上不同的等待隊列,我們也可以獲取不同的等待隊列來實現。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T09_00_lock_condition {

    public static void main(String[] args) {

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        Lock lock = new ReentrantLock();
        Condition conditionT1 = lock.newCondition();
        Condition conditionT2 = lock.newCondition();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aI) {
                    System.out.print(c);
                    conditionT2.signal();
                    conditionT1.await();
                }

                conditionT2.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t1").start();

        new Thread(()->{
            try {
                lock.lock();

                for(char c : aC) {
                    System.out.print(c);
                    conditionT1.signal();
                    conditionT2.await();
                }

                conditionT1.signal();

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

        }, "t2").start();
    }
}

4. 使用TransferQueue阻塞隊列

TransferQueue是Java并發包中的一個阻塞隊列,它可以用于多線程之間的數據交換和同步。

LinkedTransferQueue繼承自TransferQueue,并且還可以支持異步操作。

圖片圖片

LinkedTransferQueue的take()方法和transfer()方法都是用于從隊列中取出元素的方法,但它們的使用場景和行為有所不同。

take()方法是一個阻塞方法,它會一直阻塞直到隊列中有可用元素,才將隊列中的元素取出并返回。

transfer()方法也是一個阻塞方法,它會將指定的元素插入到隊列中,并等待另一個線程從隊列中取出該元素。如果隊列中沒有等待的線程,則當前線程會一直阻塞,直到有其他線程從隊列中取走該元素為止。

那么我們就利用這一點它必須要另外一個線程來取進而實現把值交替輸出。

import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;

public class T13_TransferQueue {
    public static void main(String[] args) {
        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        TransferQueue<Character> queue = new LinkedTransferQueue<Character>();
        new Thread(()->{
            try {
                for (char c : aI) {
                    System.out.print(queue.take());
                    queue.transfer(c);
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t1").start();

        new Thread(()->{
            try {
                for (char c : aC) {
                    queue.transfer(c);
                    System.out.print(queue.take());
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "t2").start();
    }
}

運行結果:

圖片圖片

5. 使用LockSupport

LockSupport是Java并發包中的一個工具類,它可以用于線程的阻塞和喚醒。

你可以把它類比成Object的wait()和notify()方法,但LockSupport是比它們更加靈活和可控的。

LockSupport提供了park()和unpark()方法:

當一個線程調用park()方法時,它會被阻塞,直到另一個線程調用該線程的unpark()方法才會被喚醒。

如果調用unpark()方法時,該線程還沒有調用park()方法,則該線程調用park()方法時不會被阻塞,可以直接返回。

import java.util.concurrent.locks.LockSupport;

//Locksupport park 當前線程阻塞(停止)
//unpark(Thread t)

public class T02_00_LockSupport {


    static Thread t1 = null, t2 = null;

    public static void main(String[] args) throws Exception {
        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        t1 = new Thread(() -> {

                for(char c : aI) {
                    System.out.print(c);
                    LockSupport.unpark(t2); //叫醒T2
                    LockSupport.park(); //T1阻塞
                }

        }, "t1");

        t2 = new Thread(() -> {

            for(char c : aC) {
                LockSupport.park(); //t2阻塞
                System.out.print(c);
                LockSupport.unpark(t1); //叫醒t1
            }

        }, "t2");

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

運行結果:

圖片圖片

6. 使用枚舉類作同步標志

創建一個枚舉類ReadyToRun,利用while(true)死等和枚舉類指向對象不同作標志位交替輸出。

public class T03_00_cas {

    enum ReadyToRun {T1, T2}

    static volatile ReadyToRun r = ReadyToRun.T1; 

    public static void main(String[] args) {

        char[] aI = "1234567".toCharArray();
        char[] aC = "ABCDEFG".toCharArray();

        new Thread(() -> {

            for (char c : aI) {
                while (r != ReadyToRun.T1) {}
                System.out.print(c);
                r = ReadyToRun.T2;
            }

        }, "t1").start();

        new Thread(() -> {

            for (char c : aC) {
                while (r != ReadyToRun.T2) {}
                System.out.print(c);
                r = ReadyToRun.T1;
            }
        }, "t2").start();
    }
}

運行結果:

圖片圖片

總結

好了,關于這個面試題的解法了不起暫時就想到這6種情況。

這個面試題也是一道經典的多線程面試題,如果你能將這幾種情況掌握,定會另面試官刮目相看。

如果你們還有新的方法歡迎和了不起一起探討研究,畢竟代碼是死的人是活的。

責任編輯:武曉燕 來源: Java面試教程
相關推薦

2024-05-10 07:44:23

C#進程程序

2024-08-28 11:10:53

2024-11-15 11:00:00

C#多線程

2011-05-26 10:55:39

2024-12-03 00:44:50

2009-08-12 18:04:44

編寫C#多線程

2012-05-18 10:36:20

CC++編程

2021-03-05 07:38:52

C++線程編程開發技術

2023-05-03 09:01:41

CanvasWebGL

2009-08-26 14:35:00

用C#實現HTTP協議

2024-12-30 06:00:00

C#線程編程

2015-03-24 13:46:29

C++多線程計數器特性實現

2011-09-07 10:00:53

Ubuntu3D

2021-02-25 15:58:46

C++線程編程開發技術

2009-08-17 16:56:51

C#多線程控制進度條

2023-01-28 09:50:17

java多線程代碼

2010-01-18 14:09:58

C++多線程

2010-02-04 10:19:39

C++多線程

2010-02-05 15:30:54

C++多線程測試

2009-08-28 16:43:57

C#多線程學習
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲视频区 | 黄色成人免费看 | 欧美日韩国产一区二区三区 | 97免费在线观看视频 | 午夜色播 | 免费在线观看成年人视频 | eeuss国产一区二区三区四区 | 欧美亚洲第一区 | 欧美日韩一区精品 | 亚洲最大的黄色网址 | 美国一级黄色片 | 国产免国产免费 | 北条麻妃一区二区三区在线视频 | 精品欧美一区二区三区久久久小说 | 欧美二区三区 | 国产黄色网址在线观看 | 99国产精品99久久久久久 | 久久com| 欧美区日韩区 | 亚洲精品一区二区三区在线观看 | 亚洲精品福利视频 | 亚洲精品自拍 | 免费看爱爱视频 | 国产精品99一区二区 | 91精品福利 | 日本成人午夜影院 | 北条麻妃av一区二区三区 | 亚洲色片网站 | 特黄视频 | 亚洲91视频 | 日韩综合一区 | 99成人精品| 久久看看 | 日本免费在线看 | 中文字幕在线观看日韩 | 亚洲三区在线播放 | 国产精品视频久久久 | 日本天堂视频在线观看 | 九九精品在线 | 麻豆精品国产91久久久久久 | 亚洲高清在线免费观看 |