前兩篇介紹了一些Java並發的基礎知識,博主正巧遇到一種需求:查詢數據庫,根據查詢結果集修改數據庫記錄,但整個流程是做成了一個schedule的,並且查詢比較耗時,並且需要每兩分鍾執行一次,cpu經常因等待服務器響應的查詢結果而進入等待,故需要在此基礎上考慮性能優化,sql優化可以提高一些系統效率,同樣,多線程也可以...
下面博主做個DEMO引出一些Java並發的實際應用場景:
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class TestThread implements Runnable{ private String name; private Integer i = 0; List list = new ArrayList(); public TestThread(String name) { this.name=name; for(int i=0; i<100; i++){ list.add(i); } } @Override public void run() { Long past = System.currentTimeMillis(); get(); System.out.println(System.currentTimeMillis()-past); } private void get(){ while(true){ try{ Thread.sleep(200); }catch(Exception e){ e.printStackTrace(); } synchronized (i){ if(i>=100){ break; } System.out.println(list.get(i++)); } } } public static void main(String[] args) { //線程池方式 ExecutorService exector = new ThreadPoolExecutor(5, 7, 30, TimeUnit.MINUTES, new ArrayBlockingQueue<>(10)); //對於最大線程數和核心線程數的參考值,對於cpu密集型任務,可以選擇NCPU+1,對於耗時較長的IO操作,可以選擇2*NCPU TestThread a = new TestThread("A"); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); exector.execute(a); //普通方式 /*TestThread a = new TestThread("A"); new Thread(a).start(); new Thread(a).start(); new Thread(a).start(); new Thread(a).start();*/ } }
TIP:不推薦使用Executors.newFixedThreadPool()來創建線程池,大家看底層代碼:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
newFixedThreadPool()方法底層還是調用了new ThreadPoolExecutor(),但線程等待隊列(LinkedBlockingQueue)默認是不限定其長度的,意味着有大量線程入隊時,會有內存溢出的風險,推薦大家使用new ThreadPoolExecutor()來創建線程池...
通過以上代碼(可以跑)感受得到單線程和多線程的性能差距,設備越好,cpu核數越多,應該結果越明顯,當然這不是絕對的,有時我們得考慮多線程的上下文切換的時間占用率和多線程同步的性能消耗...另外,我們平常應該使用線程池來管理線程,因為比較方便,JavaAPI也已經將細節實現到位,各位可以用這樣線程安全的方式結合索引遍歷集合,這樣對於集合內的元素就可以多線程遍歷並觸發各自的操作,例如更新數據庫等,可以說非常實用...
多線程使用的主要目的在於:
1、吞吐量:你做WEB,容器幫你做了多線程,但是他只能幫你做請求層面的。簡單的說,可能就是一個請求一個線程。或多個請求一個線程。如果是單線程,那同時只能處理一個用戶的請求。
2、伸縮性:也就是說,你可以通過增加CPU核數來提升性能。如果是單線程,那程序執行到死也就利用了單核,肯定沒辦法通過增加CPU核數來提升性能。