多個線程一塊兒作同一件事情,縮短期,提高效率
提升資源利用率
加快程序響應,提高用戶體驗java
經過前面的學習,能夠看到,無論何種建立對象的方式,都須要新創建實例,因此咱們能夠經過構造函數傳入參數,並將傳入的數據使用類變量保存起來緩存
在線程類裏面定義一些列的變量,而後定義set方法,在新建實例以後,調用set方法傳遞參數安全
使用線程方法本身產生的變量值做爲參數,去調取外部的方法,獲取返回數據的方式多線程
要跨線程維護正確的可見性,只要在幾個線程之間共享非 final 變量,就必須使用線程同步併發
ThreadLocal利用空間換時間,經過爲每一個線程提供一個獨立的變量副本,避免了資源等待,解決了變量併發訪問的衝突問題,提升了併發量。實現了線程間的數據隔離,可是線程間沒法共享同一個資源異步
public class StudyThread { public static void main(String[] args) throws ExecutionException, InterruptedException { SyncTest syncTest = new SyncTest(); ConcurrentHashMap<String, String> testConMap = new ConcurrentHashMap<>(); for (int i = 0; i < 10; i++) { ThreadTest2 threadTest2 = new ThreadTest2(); threadTest2.setSyncTest(syncTest); Thread threadTest = new Thread(threadTest2); threadTest.start(); } } } //實現Runnable class ThreadTest2 implements Runnable { private SyncTest syncTest; public void setSyncTest(SyncTest syncTest) { this.syncTest = syncTest; } @Override public void run() { syncTest.threadLocalTest(Thread.currentThread().getName()); } } class SyncTest { private static ThreadLocal<String> threadLocal = new ThreadLocal<String>(); public void threadLocalTest(String name) { try { System.out.println(name + "進入了threadLocal方法!"); threadLocal.set(name); Thread.currentThread().sleep(100); System.out.println(threadLocal.get() + "離開了threadLocal方法!"); } catch (InterruptedException e) { e.printStackTrace(); } } }
無論synchronized是用來修飾方法,仍是修飾代碼塊,其本質都是鎖定某一個對象。修飾方法時,鎖上的是調用這個方法的對象,即this;修飾代碼塊時,鎖上的是括號裏的那個對象ide
public class StudyThread { public static void main(String[] args) throws ExecutionException, InterruptedException { SyncTest syncTest = new SyncTest(); ConcurrentHashMap<String, String> testConMap = new ConcurrentHashMap<>(); for (int i = 0; i < 10; i++) { ThreadTest2 threadTest2 = new ThreadTest2(); threadTest2.setSyncTest(syncTest); threadTest2.setTestConMap(testConMap); Thread threadTest = new Thread(threadTest2); threadTest.start(); } } } //實現Runnable class ThreadTest2 implements Runnable { private ConcurrentHashMap<String, String> testConMap; private SyncTest syncTest; public void setTestConMap(ConcurrentHashMap<String, String> testConMap) { this.testConMap = testConMap; } public void setSyncTest(SyncTest syncTest) { this.syncTest = syncTest; } @Override public void run() { //三個方法須要單獨測試,由於testConMap會相互影響 //測試同步方法,鎖住的對象是syncTest //syncTest.testSyncMethod(testConMap,Thread.currentThread().getName()); //測試同步代碼塊,鎖住的對象是testConMap //syncTest.testSyncObject(testConMap, Thread.currentThread().getName()); //測試沒有鎖時執行請求是多麼的混亂!!! //syncTest.testNoneSyncObject(testConMap, Thread.currentThread().getName()); } } //同步測試方法類 class SyncTest { public synchronized void testSyncMethod(ConcurrentHashMap<String, String> testConMap, String name) { try { System.out.println(name + "進入了同步方法!"); testConMap.put("name", name); Thread.currentThread().sleep(10); System.out.println(testConMap.get("name") + "離開了同步方法!"); } catch (InterruptedException e) { e.printStackTrace(); } } public void testSyncObject(ConcurrentHashMap<String, String> testConMap, String name) { synchronized (testConMap) { try { System.out.println(name + "進入了同步代碼塊!"); testConMap.put("name", name); Thread.currentThread().sleep(10); System.out.println(testConMap.get("name") + "離開了同步代碼塊!"); } catch (InterruptedException e) { e.printStackTrace(); } } } public void testNoneSyncObject(ConcurrentHashMap<String, String> testConMap, String name) { try { System.out.println(name + "進入了無人管轄區域!"); testConMap.put("name", name); Thread.currentThread().sleep(10); System.out.println(testConMap.get("name") + "離開了無人管轄區域!"); } catch (InterruptedException e) { e.printStackTrace(); } } }
特色函數
public class StudyThread { static int v = 1;//volatile可以保證變量的可見性 public static void main(String[] args) { //改動線程 new Thread(new Runnable() { public void run() { for (int i = 0; i < 10; i++) { v++;//確保只有一個線程修改變量值 try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); //檢測線程 new Thread(new Runnable() { @Override public void run() { int old = 0; while (old < 11) { if (old != v) { old = v; System.out.println("檢測線程:v的值變更爲" + old); } } } }).start(); } }
Java中不少類說的線程安全指的是,它的每一個方法單獨調用(即原子操做)都是線程安全的,可是代碼整體的互斥性並不受控制學習
線程安全的類有如下幾類測試
Concurrentxxx
ThreadPoolExecutor
BlockingQueue和BlockingDeque
原子類Atomicxxx—包裝類的線程安全類
CopyOnWriteArrayList和CopyOnWriteArraySet
經過synchronized 關鍵字給方法加上內置鎖來實現線程安全:Timer,TimerTask,Vector,Stack,HashTable,StringBuffer
Collections中的synchronizedCollection(Collection c)方法可將一個集合變爲線程安全:
Map m=Collections.synchronizedMap(new HashMap());
線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類
public class StudyThread { public static void main(String[] args) throws ExecutionException, InterruptedException { //建立一個線程池,該線程池重用固定數量的從共享無界隊列中運行的線程 //ExecutorService threadPool = Executors.newFixedThreadPool(20); //建立一個維護足夠的線程以支持給定的並行級別的線程池,線程的實際數量能夠動態增加和收縮,工做竊取池不保證執行提交的任務的順序 //ExecutorService threadPool = Executors.newWorkStealingPool(8); //建立一個使用從無界隊列運行的單個工做線程的執行程序。 //ExecutorService threadPool = Executors.newSingleThreadExecutor(); //建立一個根據須要建立新線程的線程池,但在可用時將從新使用之前構造的線程。若是沒有可用的線程,將建立一個新的線程並將其添加到該池中。未使用六十秒的線程將被終止並從緩存中刪除 ExecutorService threadPool = Executors.newCachedThreadPool(); //放入Runnable類線程 for (int i = 0; i < 10; i++) { threadPool.execute(new Runnable() { @Override public void run() { System.out.println("線程名:" + Thread.currentThread().getName()); } }); } //Thread.currentThread().sleep(1000); //放入Callable類線程 List<Future<String>> futures = new ArrayList<>(); for (int i = 0; i < 10; i++) { Future<String> future = threadPool.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("線程名:" + Thread.currentThread().getName()); return Thread.currentThread().getName(); } }); futures.add(future); } threadPool.shutdown(); for (Future future : futures) { System.out.println(future.get()); } } }
要點
public class StudyThread { public static void main(String[] args) throws ExecutionException, InterruptedException { int poolSize = Runtime.getRuntime().availableProcessors() * 2; BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(512); RejectedExecutionHandler policy = new ThreadPoolExecutor.DiscardPolicy(); ExecutorService executorService = new ThreadPoolExecutor(poolSize, poolSize, 0, TimeUnit.SECONDS, queue, policy); //放入Runnable類線程 for (int i = 0; i < 10; i++) { executorService.execute(new Runnable() { @Override public void run() { System.out.println("線程名:" + Thread.currentThread().getName()); } }); } //放入Callable類線程 List<Future<String>> futures = new ArrayList<>(); for (int i = 0; i < 10; i++) { Future<String> future = executorService.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("線程名:" + Thread.currentThread().getName()); return Thread.currentThread().getName(); } }); futures.add(future); } for (Future future:futures) { System.out.println(future.get()); } //放入Callable類線程 //使用CompletionService簡化獲取結果的操做,執行完一個任務,獲取一個結果,結果順序和執行順序相同 CompletionService<String> ecs = new ExecutorCompletionService<String>(executorService); for (int i = 0; i < 10; i++) { Future<String> future = ecs.submit(new Callable<String>() { @Override public String call() throws Exception { System.out.println("線程名:" + Thread.currentThread().getName()); return Thread.currentThread().getName(); } }); } for (int i = 0; i < 10; i++) { System.out.println(ecs.take().get()); } } }