一個簡單的java多線程例子,java多線程

來源:互聯網
上載者:User

一個簡單的java多線程例子,java多線程

現在有這樣一個任務,有一份手機號列表(20W),有一份話單的列表(10W),要統計哪些手機號沒有出現在話單中,哪些手機號在話單中出現了不止一次。

想到的最直接的方式,就是兩層迴圈去遍曆,雖然此方法比較笨,但目前還沒有想出更好的辦法。

一開始使用單線程來處理,代碼是隨手寫的並沒有進行重構,只是做一個簡單的說明:

package tool;import java.util.List;public class SingleThread{public static void main(String[] args){SingleThread st = new SingleThread();String userIdPath = "D:\\shell\\store_bak\\tool\\userid.txt";List<String> userIds = Util.readUserId(userIdPath);List<String> cdrItems = Util.readCdrItem();st.process(userIds, cdrItems);}/** *  * @param userIds * @param cdrItems */private void process(List<String> userIds, List<String> cdrItems){long startTime = System.currentTimeMillis();int count = 0;for (String key : userIds){String[] uninKeys = key.split("\\s+");count = 0;for (String cdr : cdrItems){if (cdr.contains("|" + uninKeys[0] + "|")&& cdr.contains("|" + uninKeys[1] + "|")){count++;}}}System.out.println((System.currentTimeMillis() - startTime) / 1000);}}

Util中的代碼就不給出了,就是簡單的檔案讀取操作,整個過程處理下來速度並不是太快,其中最耗時的操作在contains方法上,一開始使用的並不是contains方法,而是使用的Regex匹配,結果發現Regex的效率並不高,因此改用contains方法。但是效率還是不太理想。因此考慮使用多線程來處理。

和傳統的生產者消費者不同,這裡實際上只有消費者,因為產生未經處理資料幾乎不耗時,最容易想到的辦法就是定義個共用的index標誌,依次互斥的進行+1操作,因此這裡的index就是一個共用的變數,需要進行同步。直接使用jdk中提供的AtomicInteger,代碼如下:

package tool;import java.util.List;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.atomic.AtomicInteger;public class MutiThread{private static AtomicInteger lock = new AtomicInteger(0);public static void main(String[] args){MutiThread tool = new MutiThread();String userIdPath = "D:\\shell\\store_bak\\tool\\userid.txt";List<String> userIds = Util.readUserId(userIdPath);List<String> cdrItems = Util.readCdrItem();tool.work2(lock, userIds, cdrItems);}public void work2(AtomicInteger lock, List<String> userIds,List<String> cdrItems){final long startTime = System.currentTimeMillis();CyclicBarrier cb = new CyclicBarrier(5, new Runnable(){@Overridepublic void run(){System.out.println((System.currentTimeMillis() - startTime) / 1000);}});for (int i = 0; i < 5; i++){new Thread(new Worker(userIds, cdrItems, lock, cb)).start();}}class Worker implements Runnable{private List<String> userIds;private List<String> cdrItems;private AtomicInteger lock;private CyclicBarrier cb;public Worker(List<String> userIds, List<String> cdrItems,AtomicInteger lock, CyclicBarrier cb){this.userIds = userIds;this.cdrItems = cdrItems;this.lock = lock;this.cb = cb;}@Overridepublic void run(){while (true){int index = lock.getAndIncrement();if (index >= userIds.size())break;String id = userIds.get(index);process1(id, cdrItems);}try{cb.await();} catch (InterruptedException e){e.printStackTrace();} catch (BrokenBarrierException e){e.printStackTrace();}}}private void process1(String id, List<String> cdrItems){String[] uninKeys = id.split("\\s+");int count = 0;for (String cdr : cdrItems){if (cdr.contains("|" + uninKeys[0] + "|")&& cdr.contains("|" + uninKeys[1] + "|")){count++;}}}}

使用多線程的方式確實能夠提高不少效率,尤其是資料量大的時候,至少是兩倍的速度,這裡的線程數也不是越多越好,因為JVM對線程的調度也會消耗資源。

針對這個情境,考慮下concurrenthashmap的實現,可以將資源進行分段處理,可以巧妙的避開多線程的資源徵用,因此可以將list分成不同的段,交給不同的線程去處理,代碼如下:

package tool;import java.util.List;import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.atomic.AtomicInteger;public class MutiSegmentMutiThread{private static AtomicInteger lock = new AtomicInteger(0);private static int ThreadNum = 10;public static void main(String[] args){MutiSegmentMutiThread tool = new MutiSegmentMutiThread();String userIdPath = "D:\\shell\\store_bak\\tool\\userid.txt";List<String> userIds = Util.readUserId(userIdPath);List<String> cdrItems = Util.readCdrItem();tool.work2(lock, userIds, cdrItems);}public void work2(AtomicInteger lock, List<String> userIds,List<String> cdrItems){final long startTime = System.currentTimeMillis();CyclicBarrier cb = new CyclicBarrier(ThreadNum, new Runnable(){@Overridepublic void run(){System.out.println((System.currentTimeMillis() - startTime) / 1000);}});int segmentSize = userIds.size() / ThreadNum;int start = 0;int end = 0;for (int i = 0; i < ThreadNum; i++){start = i * segmentSize;if (i == ThreadNum - 1){end = userIds.size();} else{end = (i + 1) * segmentSize;}new Thread(new Worker(userIds, cdrItems, cb, start, end)).start();}}class Worker implements Runnable{private List<String> userIds;private List<String> cdrItems;private CyclicBarrier cb;private int start;private int end;public Worker(List<String> userIds, List<String> cdrItems,CyclicBarrier cb, int start, int end){this.userIds = userIds;this.cdrItems = cdrItems;this.cb = cb;this.start = start;this.end = end;}@Overridepublic void run(){for (int i = start; i < end; i++){String id = userIds.get(i);process1(id, cdrItems);}try{cb.await();} catch (InterruptedException e){e.printStackTrace();} catch (BrokenBarrierException e){e.printStackTrace();}}}private void process1(String id, List<String> cdrItems){String[] uninKeys = id.split("\\s+");int count = 0;for (String cdr : cdrItems){if (cdr.contains("|" + uninKeys[0] + "|")&& cdr.contains("|" + uninKeys[1] + "|")){count++;}}}}

實際測試中第三種方式確實比第二種要快些,但是提升並不是很明顯。以上的代碼只是為解決問題提供一個思路,想必還能夠繼續最佳化,如果資料量非常大,可以考慮使用分散式運算了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.