• 多线程_分析词频我们到底能走多远系列(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

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

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

     

  • 相关阅读:
    假期十一
    假期十
    假期九
    假期八
    假期七
    假期六
    假期五
    假期四
    2020.02.11
    2020.02.10
  • 原文地址:https://www.cnblogs.com/killbug/p/2668007.html
Copyright © 2020-2023  润新知