我們到底能走多遠系列(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
----------------------------------------------------------------------
努力不一定成功,但不努力肯定不會成功。
共勉。
