多線程_分析詞頻-我們到底能走多遠系列(5)


我們到底能走多遠系列(5)

一日不扯淡,便覺空虛迷茫

  西瓜不是切出來的,房子不是畫出來的,人生卻是磨出來的。

  前天,坐旁邊的8年C++高手辭職走人了。磨了8年的男人,有些謝頂,有些憔悴。

  我想就算每天學到的只有一點點,8年也能悟出不少東西來吧。我想他雖不是及其努力的那種,但憑着對編程技術或者知識的愛好,不自然的會去學到很多東西。這幾個月接觸下來他,發現他幾個工作上的幾個點:

  1,編碼的時候,基本是不用google的。(google都是在編碼開始前搞的大概)

  2,出錯,異常,問題的時候,直接看底層實現。因為有時候他會抱怨怎么沒有提供底層代碼包。

  3,很關注和自己作用的技術有關的新聞,然后和我扯淡...

  4,功能實現的時候,基本在考慮怎樣的設計模式會更好。(一位5年經驗的哥哥評論他的代碼是說:這不是java嘛...)

難道我們8年后也是這樣編程嗎?沒有優勢,也就只能用時間去填。

說實話,我感覺園子里搞java的很少啊,至少要比.net的少多了,每天有時間看看你們寫的blog,沒找到幾篇是關於java的。

 

寫幾句代碼,只是為了保持編程的敏感度。

最近,一直在學英語,就像能不能寫個程序把一篇文章的或者很多文章的單詞都集中起來,然后分析出單詞的出現頻率。

寫了個簡單的程序后,然后想,是不是順便學習下java的多線程。然后就有了下面很挫的代碼。

 

 程序的結構:

實現:

package code.words;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class WordsAnalysis {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        
        File f = new File("d:\\我的文檔\\test");
        File[] fs = f.listFiles();
        // 分成兩半
        List<File> files1 = new ArrayList<File>();
        for (int i = 0; i < fs.length/2; i++) {
            files1.add(fs[i]);
            
        }
        List<File> files2 = new ArrayList<File>();
        for (int i = fs.length/2; i < fs.length; i++) {
            files2.add(fs[i]);
            
        }
        // 工作線程總數
        int threadCount = 0;
        // 共享數據
        AllCountModel acm = new AllCountModel();
        acm.setThreadCount(++threadCount);
        ThreadTest tt1 = new ThreadTest(files1, acm);
        // 1號線程
        tt1.start();
        acm.setThreadCount(++threadCount);
        ThreadTest tt2 = new ThreadTest(files2, acm);
        // 2號線程
        tt2.start();
        MonitorThread mt = new MonitorThread(acm);
        // 監視線程
        mt.start();
        
    }
    
    /**
     * 
     * @param file
     * @param wordsMap
     * @return
     * @throws IOException
     */
    public Map<String, Integer> countWords(File file, Map<String, Integer> wordsMap) throws IOException{
        
        // 讀流
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        // 一行字符串
        String str;
        // 讀取每一行
        while((str = reader.readLine()) != null ){
            str = str.trim();
            // 跳過空行
            if(str.equals("") || str == null){
                continue;
            }
            // 按空格分離成單詞
            String[] strs = str.split(" ");
            for (int i = 0; i < strs.length; i++) {
                String word = strs[i].trim();
                // 重現的單詞
                if(wordsMap.containsKey(word)){
                    // 計數
                    wordsMap.put(word, (wordsMap.get(word) + 1));
                }else{
                    // 第一次出現的新單詞
                    wordsMap.put(word, 1);
                }
            }
        }
        // 關閉流
        reader.close();
        return wordsMap;
    }
    
    /**
     * 打印結果
     * @param AllCountModel 共享的結果集
     */
    public static void show(AllCountModel acm){
        System.out.println(acm.getThreadCount());
        for (List<File> lists : acm.getLastMap().keySet()) {
            System.out.println(lists);
            for (String str : acm.getLastMap().get(lists).keySet()) {
                System.out.println(str + " : " + acm.getLastMap().get(lists).get(str));
            }
            System.out.println("------------------------------------------");
        }
        
    }
}

1,共享數據類

View Code
package code.words;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class AllCountModel {

    // 在運行的線程總數
    private int threadCount;

    // 每個線程處理的文件對應的結果集
    private HashMap<List<File>, Map<String, Integer>> lastMap = new HashMap<List<File>, Map<String, Integer>>();
    
    public int getThreadCount() {
        return threadCount;
    }
    public void setThreadCount(int threadCount) {
        this.threadCount = threadCount;
    }
    public HashMap<List<File>, Map<String, Integer>> getLastMap() {
        return lastMap;
    }
    public void setLastMap(HashMap<List<File>, Map<String, Integer>> lastMap) {
        this.lastMap = lastMap;
    }
}

2,工作線程

View Code
package code.words; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.HashMap; import java.util.Map; public class ThreadTest extends Thread{ private List<File> files = new ArrayList<File>(); private Map<String, Integer> wordsMap = new HashMap<String, Integer>(); private AllCountModel allCountModel; // 每一個線程都傳入不一樣的files,所以不用擔心這個對象的同步沖突
    public ThreadTest(List<File> files, AllCountModel allCountModel){ this.files = files; this.allCountModel = allCountModel; } public void run() { WordsAnalysis wa = new WordsAnalysis(); // 解析傳入的全部文件
        for (File file : files) { try { // 解析文件內容
                wordsMap = wa.countWords(file, wordsMap); } catch (IOException e) { e.printStackTrace(); } } // 鎖住共享數據(必須這么做,否則共享的數據會紊亂)
        synchronized (allCountModel) { // 更新線程總數
            allCountModel.setThreadCount(allCountModel.getThreadCount() - 1); // 更新結果集
 allCountModel.getLastMap().put(files, wordsMap); } } }

3,檢測線程

View Code
package code.words;

public class MonitorThread extends Thread{

    // 共享數據
    private AllCountModel acm;
    
    public MonitorThread(AllCountModel acm){
        this.acm = acm;
    }
    
    public void run() {
        while(true){
            try {
                // 隔段時間檢查一次
                sleep(500); 
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 線程全部工作完畢
            if(0 >= acm.getThreadCount()){
                // 打印出結果
                WordsAnalysis.show(acm);
                return;
            }
        }
    }
}

4,主程序

package code.words;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class WordsAnalysis {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {
        
        File f = new File("d:\\我的文檔\\test");
        File[] fs = f.listFiles();
        // 分成兩半
        List<File> files1 = new ArrayList<File>();
        for (int i = 0; i < fs.length/2; i++) {
            files1.add(fs[i]);
            
        }
        List<File> files2 = new ArrayList<File>();
        for (int i = fs.length/2; i < fs.length; i++) {
            files2.add(fs[i]);
            
        }
        // 工作線程總數
        int threadCount = 0;
        // 共享數據
        AllCountModel acm = new AllCountModel();
        acm.setThreadCount(++threadCount);
        ThreadTest tt1 = new ThreadTest(files1, acm);
        // 1號線程
        tt1.start();
        acm.setThreadCount(++threadCount);
        ThreadTest tt2 = new ThreadTest(files2, acm);
        // 2號線程
        tt2.start();
        MonitorThread mt = new MonitorThread(acm);
        // 監視線程
        mt.start();
        
    }
    
    /**
     * 
     * @param file
     * @param wordsMap
     * @return
     * @throws IOException
     */
    public Map<String, Integer> countWords(File file, Map<String, Integer> wordsMap) throws IOException{
        
        // 讀流
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
        // 一行字符串
        String str;
        // 讀取每一行
        while((str = reader.readLine()) != null ){
            str = str.trim();
            // 跳過空行
            if(str.equals("") || str == null){
                continue;
            }
            // 按空格分離成單詞
            String[] strs = str.split(" ");
            for (int i = 0; i < strs.length; i++) {
                String word = strs[i].trim();
                // 重現的單詞
                if(wordsMap.containsKey(word)){
                    // 計數
                    wordsMap.put(word, (wordsMap.get(word) + 1));
                }else{
                    // 第一次出現的新單詞
                    wordsMap.put(word, 1);
                }
            }
        }
        // 關閉流
        reader.close();
        return wordsMap;
    }
    
    /**
     * 打印結果
     * @param AllCountModel 共享的結果集
     */
    public static void show(AllCountModel acm){
        System.out.println(acm.getThreadCount());
        for (List<File> lists : acm.getLastMap().keySet()) {
            System.out.println(lists);
            for (String str : acm.getLastMap().get(lists).keySet()) {
                System.out.println(str + " : " + acm.getLastMap().get(lists).get(str));
            }
            System.out.println("------------------------------------------");
        }
        
    }
}

改進:還有很多需要改進的地方:比如分析單詞時,需要更加精准,沒有過濾掉非單詞內容;線程上的設計完全是憑空想出來的,一定還有更好的線程結構可以代替。

------------------------------------------------

多線程帶來的數據共享問題和synchronized關鍵字的作用:

為什么多線程會引起數據沖突呢:

package code.mytest;

public class Test1 extends Thread{

    private String[] strs;
    
    public Test1(String[] strs){
        this.strs = strs;
    }
    
    @Override
    public void run() {
        
        while(true){
            strs[0] = strs[0] + "A";
            System.out.println(strs[0]);
            try {
                sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }

    public static void main(String[] args) {
        String[] strs = new String[]{"A"};
        Test1 t1 = new Test1(strs);
        Test1 t2 = new Test1(strs);
        Test1 t3 = new Test1(strs);
        t1.start();
        t2.start();
        t3.start();
    }
}

上面代碼執行的結果:只管的可以理解到為什么要注意共享數據這個事情了

AA
AAAA
AAA
AAAAA
AAAAAA
AAAAAAA
AAAAAAAA
AAAAAAAAA
AAAAAAAAAA
AAAAAAAAAAA
AAAAAAAAAAAA
AAAAAAAAAAAAA
AAAAAAAAAAAAAA
AAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAA

 那么用synchronized關鍵字后的效果:

    public void run() {
        
        while(true){
            // 保證在處理strs時,其他線程不能動這個數據,從而避免了數據沖突
            synchronized (strs) {
                strs[0] = strs[0] + "A";
            }
            System.out.println(strs[0]);
            try {
                sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }

執行的結果:

AA
AAA
AAAA
AAAAA
AAAAAA
AAAAAAA
AAAAAAAA
AAAAAAAAA
AAAAAAAAAA
AAAAAAAAAAA
AAAAAAAAAAAA
AAAAAAAAAAAAA

 希望能帶給你理解上的幫助。

------------------------------------------------------------

送給各位一句話:來自《天國王朝》

be without fear in the face of enemies
be brave and upright that god may love thee
speak the truth even if leads to your death

----------------------------------------------------------------------

努力不一定成功,但不努力肯定不會成功。
共勉。

 


免責聲明!

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



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