1. 程式人生 > >你會這道阿里多執行緒面試題嗎?

你會這道阿里多執行緒面試題嗎?

開發十年,就只剩下這套架構體系了! >>>   

背景

在前幾天,群裡有個群友問了我一道面試阿里的時候遇到的多執行緒題目,這個題目比較有意思,在這裡和大家分享一下。

廢話不多說,直接上題目:

通過N個執行緒順序迴圈列印從0至100,如給定N=3則輸出:
thread0: 0
thread1: 1
thread2: 2
thread0: 3
thread1: 4
.....

一些經常刷面試題的朋友,之前肯定遇到過下面這個題目:

兩個執行緒交替列印0~100的奇偶數:
偶執行緒:0
奇執行緒:1
偶執行緒:2
奇執行緒:3

這兩個題目看起來相似,第二個題目稍微來說比較簡單一點,大家可以先思考一下兩個執行緒奇偶數如何列印。

兩執行緒奇偶數列印

有一些人這裡可能會用討巧的,用一個執行緒進行迴圈,在每次迴圈裡面都會做是奇數還是偶數的判斷,然後打印出這個我們想要的結果。在這裡我們不過多討論這種違背題目本意的做法。

其實要做這個題目我們就需要控制兩個執行緒的執行順序,偶執行緒執行完之後奇數執行緒執行,這個有點像通知機制,偶執行緒通知奇執行緒,奇執行緒再通知偶執行緒。而一看到通知/等待,立馬就有朋友想到了Object中的wait和notify。沒錯,這裡我們用wait和notify對其進行實現,程式碼如下:

public class 交替列印奇偶數 {
    static class SoulutionTask implements Runnable{
        static int value = 0;
        @Override
        public void run() {
            while (value <= 100){
                synchronized (SoulutionTask.class){
                    System.out.println(Thread.currentThread().getName() + ":" + value++);
                    SoulutionTask.class.notify();
                    try {
                        SoulutionTask.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public static void main(String[] args) {
        new Thread(new SoulutionTask(), "偶數").start();
        new Thread(new SoulutionTask(), "奇數").start();
    }
}

這裡我們有兩個執行緒,通過notify和wait用來控制我們執行緒的執行,從而打印出我們目標的結果

N個執行緒迴圈列印

再回到我們最初的問題來,N個執行緒進行迴圈列印,這個問題我再幫助群友解答了之後,又再次把這個問題在群裡面拋了出來,不少老司機之前看過交替列印奇偶數這道題目,於是馬上做出了幾個版本,讓我們看看老司機1的程式碼:

public class 老司機1 implements Runnable {

    private static final Object LOCK = new Object();
    /**
     * 當前即將列印的數字
     */
    private static int current = 0;
    /**
     * 當前執行緒編號,從0開始
     */
    private int threadNo;
    /**
     * 執行緒數量
     */
    private int threadCount;
    /**
     * 列印的最大數值
     */
    private int maxInt;

    public 老司機1(int threadNo, int threadCount, int maxInt) {
        this.threadNo = threadNo;
        this.threadCount = threadCount;
        this.maxInt = maxInt;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (LOCK) {
                // 判斷是否輪到當前執行緒執行
                while (current % threadCount != threadNo) {
                    if (current > maxInt) {
                        break;
                    }
                    try {
                        // 如果不是,則當前執行緒進入wait
                        LOCK.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                // 最大值跳出迴圈
                if (current > maxInt) {
                    break;
                }
                System.out.println("thread" + threadNo + " : " + current);
                current++;
                // 喚醒其他wait執行緒
                LOCK.notifyAll();
            }
        }
    }

    public static void main(String[] args) {
        int threadCount = 3;
        int max = 100;
        for (int i = 0; i < threadCount; i++) {
            new Thread(new 老司機1(i, threadCount, max)).start();
        }
    }
}

核心方法在run裡面,可以看見和我們交替列印奇偶數原理差不多,這裡將我們的notify改成了notifyAll,這裡要注意一下很多人會將notifyAll理解成其他wait的執行緒全部都會執行,其實是錯誤的。這裡只會將wait的執行緒解除當前wait狀態,也叫作喚醒,由於我們這裡用同步鎖synchronized塊包裹住,那麼喚醒的執行緒會做會搶奪同步鎖。

這個老司機的程式碼的確能跑通,但是有一個問題是什麼呢?當我們執行緒數很大的時候,由於我們不確定喚醒的執行緒到底是否是下一個要執行的就有可能會出現搶到了鎖但不該自己執行,然後又進入wait的情況,比如現在有100個執行緒,現在是第一個執行緒在執行,他執行完之後需要第二個執行緒執行,但是第100個執行緒搶到了,發現不是自己然後又進入wait,然後第99個執行緒搶到了,發現不是自己然後又進入wait,然後第98,97...直到第3個執行緒都搶到了,最後才到第二個執行緒搶到同步鎖,這裡就會白白的多執行很多過程,雖然最後能完成目標。

還有其他老司機用lock/condition也實現了這樣的功能,還有老司機用比較新穎的方法比如佇列去做,當然這裡就不多提了,大致的原理都是基於上面的,這裡我說一下我的做法,在Java的多執行緒中提供了一些常用的同步器,在這個場景下比較適合於使用Semaphore,也就是訊號量,我們上一個執行緒持有下一個執行緒的訊號量,通過一個訊號量陣列將全部關聯起來,程式碼如下:

static int result = 0;
    public static void main(String[] args) throws InterruptedException {
        int N = 3;
        Thread[] threads = new Thread[N];
        final Semaphore[] syncObjects = new Semaphore[N];
        for (int i = 0; i < N; i++) {
            syncObjects[i] = new Semaphore(1);
            if (i != N-1){
                syncObjects[i].acquire();
            }
        }
        for (int i = 0; i < N; i++) {
            final Semaphore lastSemphore = i == 0 ? syncObjects[N - 1] : syncObjects[i - 1];
            final Semaphore curSemphore = syncObjects[i];
            final int index = i;
            threads[i] = new Thread(new Runnable() {

                public void run() {
                    try {
                        while (true) {
                            lastSemphore.acquire();
                            System.out.println("thread" + index + ": " + result++);
                            if (result > 100){
                                System.exit(0);
                            }
                            curSemphore.release();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            });
            threads[i].start();
        }
    }

通過這種方式,我們就不會有白白喚醒的執行緒,每一個執行緒都按照我們所約定的順序去執行,這其實也是面試官所需要考的地方,讓每個執行緒的執行都能再你手中得到控制,這也可以驗證你多執行緒知識是否牢固。

最後這篇文章被我收錄於JGrowing-Java面試篇,一個全面,優秀,由社群一起共建的Java學習路線,如果您想參與開源專案的維護,可以一起共建,github地址為:https://github.com/javagrowing/JGrowing 麻煩給個小星星喲。

如果大家覺得這篇文章對你有幫助,你的關注和轉發是對我最大的支援,O(∩_∩)O:

相關推薦

阿里執行試題

開發十年,就只剩下這套架構體系了! >>>   

精選20Java執行試題並有答案!

ConcurrentHashMap的併發度就是segment的大小,預設為16,這意味著最多同時可以有16條執行緒操作ConcurrentHashMap,這也是ConcurrentHashMap對Hashtable的最大優勢,任何情況下,Hashtable能同時有兩條執行緒獲取Hashtable中的資料∂

一道阿里執行試題分析

首先,來看看這個面試題目吧。 題目來源:   http://www.linuxidc.com/Linux/2014-03/98715.htm public class MyStack { private List<String> lis

一道阿里執行試題的分析與應對

   引言: 通過多執行緒的面試題目分析,來深入理解Java執行緒的狀態轉變過程。    最近在學習Java多執行緒設計的時候,在網上看到一個面試題目的討論,雖然樓主所說有些道理,但感覺還是有些問題,故此在和同事討論以後還是有了若干收穫,在此略作總結。     首先,來看看

精選八執行試題,來看看幾個?

Java是一種可以撰寫跨平臺應用軟體的面向物件的程式設計語言。Java 技術具有卓越的通用性、高效性、平臺移植性和安全性,廣泛應用於PC、資料中心、遊戲控制檯、科學超級計算機、行動電話和網際網路,同時擁有全球最大的開發者專業社群。 一、多執行緒有幾種實現方案,分別是哪幾種? 三種。 1.

40阿里巴巴JAVA研發崗執行試題詳解,能答出多少

1、多執行緒有什麼用? 一個可能在很多人看來很扯淡的一個問題:我會用多執行緒就好了,還管它有什麼用?在我看來,這個回答更扯淡。

想進大廠?50個執行試題多少?(一)

最近看到網上流傳著,各種面試經驗及面試題,往往都是一大堆技術題目貼上去,而沒有答案。 不管你是新程式設計師還是老手,你一定在面試中遇到過有關執行緒的問題。Java語言一個重要的特點就是內建了對併發的支援,讓Java大受企業和程式設計師的歡迎。大多數待遇豐厚的J

Java程式設計師金三銀四求職季,這些執行試題

  多執行緒是Java技術面試中面試官比較喜歡問的問題之一。在這裡,從面試的角度列出了大部分重要的問題,但是作為一個程式設計師仍然應該牢固的掌握Java多執行緒基礎知識來對應日後碰到的問題。 1. 程序和執行緒之間有什麼不同? 一個程序是一個獨立(self contain

50個執行試題多少?

下面是Java執行緒相關的熱門面試題,你可以用它來好好準備面試。什麼是執行緒?什麼是執行緒安全和執行緒不安全?什麼是自旋鎖?什麼是Java記憶體模型?什麼是CAS?什麼是樂觀鎖和悲觀鎖?什麼是AQS?什麼是原子操作?在Java Concurrency API中有哪些原子類(atomic classes)?什麼

關於阿里春招的一道執行試題的個人愚見

原題如下:    多執行緒,5個執行緒內部列印hello和word,hello在前,要求提供一種方法使得5個執行緒先全部打印出hello後再列印5個word。參考文章:程式碼如下:    five.javapublic class Five { //定義一個公共鎖物件

15+N個頂級網上流行的Java執行試題及自己總結的答案(遇到即更新)

1)現在有T1、T2、T3三個執行緒,你怎樣保證T2在T1執行完後執行,T3在T2執行完後執行?直接上程式碼(所有程式均以簡單明瞭為主) 原文引用:這個執行緒問題通常會在第一輪或電話面試階段被問到,目的是檢測你對”join”方法是否熟悉。這個多執行緒問題比較簡單,可以用jo

25執行試題,附帶答案(一)

1.什麼是程序? 是一個具有一定獨立功能的程式在一個數據集上的一次動態執行的過程,是作業系統進行資源分配和排程的一個獨立單位,

「建議心心」要就來15執行試題一次爽到底(1.1w字用心整理)

、 本文是給「建議收藏」200MB大廠面試文件,整理總結2020年最強面試題庫「CoreJava篇」寫的答案,所有相關文章已經收錄在碼雲倉庫:https://gitee.com/bingqilinpeishenme/Java-interview 千上萬水總是情,先贊後看行不行,奧力給 本文為多執行緒面

BATJ都愛問的執行試題

下面最近發的一些併發程式設計的文章彙總,通過閱讀這些文章大家再看大廠面試中的併發程式設計問題就沒有那麼頭疼了。今天給大家總結一下,面試中出鏡率很高的幾個多執行緒面試題,希望對大家學習和麵試都能有所幫助。備註:文中的程式碼自己實現一遍的話效果會更佳哦! 併發程式設計面試必備:synchronized 關

Java 執行試題及答案(非常全面)

這篇文章主要是對多執行緒的問題進行總結的,因此羅列了40個多執行緒的問題。 這些多執行緒的問題,有些來源於各大網站、有些來源於自己的思考。可能有些問題網上有、可能有些問題對應的答案也有、也可能有些各位網友也都看過,但是本文寫作的重心就是所有的問題都會按照自己的理解回答一遍,不會去看網上的

Java執行試題整理(BATJ都愛問)

今天給大家總結一下,面試中出鏡率很高的幾個多執行緒面試題,希望對大家學習和麵試都能有所幫助。備註:文中的程式碼自己實現一遍的話效果會更佳哦! 一、面試中關於 synchronized 關鍵字的 5 連擊 1.1 說一說自己對於 synchronized 關鍵字的瞭解 synchroniz

Java資深架構師詳解大廠執行試題,細談併發程式設計深造歷程

  多執行緒、執行緒池 多執行緒是實現併發機制的一種有效手段。程序和執行緒一樣,都是實現併發的一個基本單位。執行緒是比程序更小的執行單位,執行緒是程序的基礎之上進行進一步的劃分。所謂多執行緒是指一個程序在執行過程中可以產生多個更小的程式單元,這些更小的單元稱為執行緒,這

java執行試題小結

http://www.importnew.com/12773.html http://www.cnblogs.com/fingerboy/p/5352880.html https://blog.csdn.net/ll666634/article/details/78615505 https://blog

Java執行試題整理

1、什麼是多執行緒 執行緒是作業系統中排程的基本單位 2、執行緒和程序的區別 執行緒是排程的基本單位,而程序是資源分配的基本單位; 3、java如何建立執行緒 繼承java.lang.Thread類 實現Runnable介面的run()方法 注:由於java只能實

15個頂級Java執行試題及回答

原文連結  ,原文作者:Javin Paul ,  譯者:趙峰 Java 執行緒面試問題 在任何Java面試當中多執行緒和併發方面的問題都是必不可少的一部分。如果你想獲得任何股票投資銀行的前臺資訊職位,那麼你應該準備很多關於多執行緒的問題。在投資銀行業務中多執行緒和併發是一個非常受歡迎的話題,