1. 程式人生 > >有四個執行緒1、2、3、4,執行緒1的功能就是輸出1,執行緒2的功能就是輸出2,以此類推......... 現在有四個檔案A B C D,初始都為空。現要讓四個檔案呈如下格式:A:1 2 3 4 1 2..

有四個執行緒1、2、3、4,執行緒1的功能就是輸出1,執行緒2的功能就是輸出2,以此類推......... 現在有四個檔案A B C D,初始都為空。現要讓四個檔案呈如下格式:A:1 2 3 4 1 2..

具體題目如下:

有四個執行緒1、2、3、4,

執行緒1的功能就是輸出1,執行緒2的功能就是輸出2,
以此類推......... 
現在有四個檔案A B C D,
初始都為空。現要讓四個檔案呈如下格式:
A:1 2 3 4 1 2....
B:2 3 4 1 2 3....
C:3 4 1 2 3 4....

D:4 1 2 3 4 1....

以上就是我看到的一個多執行緒相關的面試題,看完了 ,就想想怎麼實現。

下面就看程式碼

理論上講,都是從main方法走起,

package com.lxk.threadTest.mianShiTest.googleTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 有四個執行緒1、2、3、4。
 * <p>
 * 執行緒1的功能就是輸出1,執行緒2的功能就是輸出2,
 * <p>
 * 以此類推......... 現在有四個檔案A B C D,
 * 初始都為空。現要讓四個檔案呈如下格式:
 * A:1 2 3 4 1 2....
 * B:2 3 4 1 2 3....
 * C:3 4 1 2 3 4....
 * D:4 1 2 3 4 1....
 * <p>
 * Created by lxk on 2017/7/14
 */
public class Main {
    public static void main(String[] args) {
        FileWriteUtil util = new FileWriteUtil();
        ExecutorService service = Executors.newCachedThreadPool();
        service.execute(new WriteRunnable(util, 1, '1'));
        service.execute(new WriteRunnable(util, 2, '2'));
        service.execute(new WriteRunnable(util, 3, '3'));
        service.execute(new WriteRunnable(util, 4, '4'));
        service.shutdown();

        //new Thread(new WriteRunnable(util, 1, '1')).start();
        //new Thread(new WriteRunnable(util, 2, '2')).start();
        //new Thread(new WriteRunnable(util, 3, '3')).start();
        //new Thread(new WriteRunnable(util, 4, '4')).start();
    }
}

上面關於啟動執行緒,有2中方式,

第一種,也就是未註釋的,略顯高階點,看類名大概就知道使用的是個執行緒池的東西。這個實現姿勢有很多種。這只是其中的一個。

第二種,也就是下面註釋的程式碼,也不low,是我們常見的啟動執行緒 的方式。

然後就是我們說的那個實現多執行緒的類的實現啦

package com.lxk.threadTest.mianShiTest.googleTest;

/**
 * Created by lxk on 2017/7/14
 */
public class WriteRunnable implements Runnable {
    private final FileWriteUtil util;
    private int threadNum;
    private char value;

    /**
     * @param util      寫檔案工具類
     * @param threadNum 執行緒號
     * @param value     寫的字元
     */
    public WriteRunnable(FileWriteUtil util, int threadNum, char value) {
        this.util = util;
        this.threadNum = threadNum;
        this.value = value;
    }

    public void run() {
        /*
         * 假設迴圈6次,一直迴圈可以使用while(true)或者for(;;)
         */
        for (int i = 0; i < 6; i++) {
            synchronized (util) {
                while (threadNum != util.getCurrentThreadNum()) {
                    try {
                        util.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                util.write(value, threadNum);
                util.notifyAll();
            }
        }
    }
}

最後,就是這個寫檔案的類啦。
package com.lxk.threadTest.mianShiTest.googleTest;

import java.io.FileWriter;
import java.io.IOException;

/**
 * 此類,是四個執行緒共享的,
 * <p>
 * Created by lxk on 2017/7/14
 */
public class FileWriteUtil {
    private int currentThreadNum = 1;
    /**
     * 記錄將字元寫入檔案的次數
     */
    private int count = 0;

    private String currentFileName;

    public void write(char value, int threadNum) {
        getCurrentFileName();
        FileWriter writer = null;
        try {
            //生成檔案位置
            writer = new FileWriter("D:/test/test/" + currentFileName + ".txt", true);
            writer.write(value + " ");
            System.out.printf(
                    "ThreadNum=%d is executing. %c is written into file file%s.txt \n",
                    currentThreadNum, value, currentFileName);
            writer.flush();
            //System.out.println(count);//
            count++;
            currentThreadNum = threadNum;
        } catch (IOException e) {
            e.printStackTrace();
        }

        if (null != writer) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        getNextThreadNum();
    }

    public int getCurrentThreadNum() {
        return currentThreadNum;
    }

    public void setCurrentThreadNum(int currentThreadNum) {
        this.currentThreadNum = currentThreadNum;
    }

    /**
     * 根據寫的次數,判斷該寫哪個檔案了?A,B,C,D.
     */
    private void getCurrentFileName() {
        int temp = count % 4;
        switch (temp) {
            case 0:
                currentFileName = "A";
                break;
            case 1:
                currentFileName = "B";
                break;
            case 2:
                currentFileName = "C";
                break;
            case 3:
                currentFileName = "D";
                break;
            default:
                currentFileName = "E";
        }
    }

    private void getNextThreadNum() {
        if (count % 4 == 0) {
            if (currentThreadNum < 3) {
                currentThreadNum += 2;
            } else {
                currentThreadNum = (currentThreadNum + 2) % 4;
            }
        } else {
            if (currentThreadNum == 4) {
                currentThreadNum = 1;
            } else {
                currentThreadNum++;
            }
        }
    }
}

最後,就是看下程式碼實際執行的結果。


從列印結果看,看到了是四個執行緒在跑,而且分別寫入到ABCD四個檔案去。


注意,圖中的紅線框,奧,也可以不注意啦。

其實,說得最透徹點,就是這四個執行緒,輪著執行,

每次,都是有一個執行緒可以執行,這的執行也就是寫檔案啦,然後其他的三個都稍息,也是wait()啦。

等這個執行緒執行完畢之後,也就是寫檔案完畢之後,喚醒另外三個在wait()的執行緒,然後,設定一下,下一個可以處於執行態的執行緒,然後又開始重複了。

不能執行的,都wait(),如此往復。

這裡有個需要注意的是。

這四個執行緒都在共享操作的就是那個寫檔案工具類。也就是對這個上鎖。四個執行緒用的是一個鎖,那就可以保證執行緒安全啦。

理論,是這個理論,但是,真讓你寫,可不一定能分分鐘就寫好。