併發concurrent---2

背景:併發知識是一個程序員段位升級的體現,一樣也是進入BAT的必經之路,有必要把併發知識從新梳理一遍。java

 

併發concurrent:程序員

使用ThreadLocal能夠實現線程範圍內共享變量,線程A寫入的值和線程B獲取到的結果一致;ReentrantReadWriteLock容許多個讀線程或多個寫線程同時進行,但不容許寫線程和讀線程同時進行;使用Callable能夠獲得線程執行的返回結果;Exchanger能夠相互交換家線程執行的結果;這些使用方法大體都同樣,JDk參考文檔裏面哪裏不會點哪裏,下面寫個ThreadLocal實現線程範圍內變量共享,裏面還用到了一下餓漢模式:面試

執行結果如圖中控制檯打印,使用ThreadLocal保證了線程0和線程1讀取到的值與寫入的一致。算法

 1 import java.util.Random;  2 import java.util.concurrent.locks.ReentrantReadWriteLock;  3 import lombok.Data;  4 
 5 public class ThreadLocalTest {  6     //ThreadLocal 實現線程範圍內共享變量
 7     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();  8     private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>();  9     public static void main(String[] args) { 10         new ReentrantReadWriteLock(); 11         for(int i = 0; i<2; i++) { 12             new Thread(new Runnable() { 13  @Override 14                 public void run() { 15                     int data = new Random().nextInt(); 16  System.out.println(Thread.currentThread().getName() 17                             +" has put data: "+ data); 18                     x.set(data);  // 存的時候與當前線程相關 取的時候也是與當前線程相關 19                     //MyThreadScopeData.getInstance()拿到與本線程實例相關的對象: 不用反覆new對象來getter/setter
20                     MyThreadScopeData.getThreadInstance().setName("name: "+data); 21  MyThreadScopeData.getThreadInstance().setAge(data); 22                     new A().get(); 23                     new B().get(); 24  } 25  }).start(); 26  } 27 } 28     
29     static class A{ 30         public void get() { 31             int data = x.get(); 32             System.out.println("A from "+Thread.currentThread().getName()+" get data: "+data); 33             //MyThreadScopeData.getInstance()拿到與本線程實例相關的對象
34             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 35             System.out.println("A from "+Thread.currentThread().getName() 36                     +" getMyData: "+myData.getName() +","+myData.getAge()); 37  } 38  } 39     
40     static class B{ 41         public void get() { 42             int data = x.get(); 43             System.out.println("B from "+Thread.currentThread().getName()+" get data: "+data); 44             //MyThreadScopeData.getInstance()拿到與本線程實例相關的對象
45             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); 46             System.out.println("B from "+Thread.currentThread().getName() 47                     +" getMyData: "+myData.getName() +","+myData.getAge()); 48  } 49  } 50     
51     //設計本身線程範圍內變量的共享,不須要建立對象,只需調用線程便可用到線程內的變量
52  @Data 53     static class MyThreadScopeData{ 54         //構造方法私有化,外部沒發直接調用,可是能夠調用裏面的靜態方法
55         private MyThreadScopeData() { } 56         public static /*synchronized*/ MyThreadScopeData getThreadInstance() { 57             MyThreadScopeData instance = map.get(); 58             if (instance == null) { 59                 //餓漢模式 : 第一次來建立
60                 instance = new MyThreadScopeData(); 61  map.set(instance); 62  } 63             return instance; 64  } 65     // private static MyThreadScopeData instance = null; // new MyThreadScopeData();
66         private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); 67         private String name; 68         private int age; 69  } 70 
71 }

網上還有一個多線程面試頗有趣的題目:子線程執行10次,主線程執行100次,接着子線程再執行10次,主線程繼續再執行100次,往復循環50次;spring

 1 //Java多線程面試: 子線程執行10次,主線程執行100次,接着子線程再10次,主線程再執行100次,往復循環50次
 2 public class ThreadCommunication {  3     public static void main(String[] args) {  4      Business business = new Business();  5     new Thread(  6             new Runnable() {  7  @Override  8         public void run() {  9             for (int i = 1; i <= 50; i++) { 10  business.sub(i); 11  } 12  } 13  }).start(); 14     
15     for (int i = 1; i <= 50; i++) { 16  business.main(i); 17  } 18  } 19     
20     //把主線程和自線程執行的方法歸結到一個類(共同算法的若干方法),巧妙設計,好維護高聚合,健壯性;
21     public static class Business{ 22         //子線程方法
23         private boolean bShouldSub = true; 24         public synchronized void sub(int i) { 25             while(!bShouldSub) { 26                 //用while比if更好,能夠防止線程被僞喚醒
27                 try { 28                     this.wait(); // 若是不是子線程方法該執行的,則令其等待
29                 } catch (InterruptedException e) { 30  e.printStackTrace(); 31  } 32  } 33             for(int j = 1; j<= 10; j++) { 34                 System.out.println("sub thread sequence of "+j + ",loop of "+ i); 35  } 36             bShouldSub = false; 37             this.notify(); //喚醒主線程方法
38  } 39     
40     //主線程方法
41     public synchronized void main(int i) { 42         while(!bShouldSub) { 43             try { 44                 this.wait();  // 若是不是主線程方法該執行的,則令其等待
45             } catch (InterruptedException e) { 46  e.printStackTrace(); 47  } 48  } 49         for(int j = 1; j<= 100; j++) { 50             System.out.println("main thread sequence of "+j + ",loop of "+ i); 51  } 52         bShouldSub = true; 53         this.notify();  // 喚醒子線程方法
54  } 55  } 56 }

線程池:緩存

一、固定線程數目的線程池newFixedThreadPool;多線程

二、緩存線程數目的線程池newCachedThreadPool;併發

三、單一線程池newSingleThreadExecutor;dom

四、定時器線程池newScheduledThreadPool;ide

 1 package com.xinyan.springcloud.controller;  2 
 3 import java.util.concurrent.ExecutorService;  4 import java.util.concurrent.Executors;  5 import java.util.concurrent.TimeUnit;  6 
 7 public class ThreadPoolTest {  8     public static void main(String[] args) {  9         //固定線程數目的線程池 3個
10          ExecutorService threadPool = Executors.newFixedThreadPool(3); 11         //緩存線程數目的線程池即動態變化 當任務過來了,線程池內部會自動增長線程,空閒後線程又被回收,線程數目不定 12         //ExecutorService threadPool = Executors.newCachedThreadPool(); 13         //單一線程池 14         //ExecutorService threadPool = Executors.newSingleThreadExecutor(); 15         //往線程池中放入10個任務:
16         for(int i = 1; i<= 10; i++) { 17             final int task = i; // task被final修飾不能變了,可是i 能夠變
18             threadPool.execute(new Runnable() { 19  @Override 20                 public void run() { 21                     for(int j =1; j<=10; j++) { 22                         try { 23                             Thread.sleep(200); 24                         } catch (InterruptedException e) { 25  e.printStackTrace(); 26  } 27                         //System.out.println(Thread.currentThread().getName()+" loop of "+ j +" task is "+ task);
28  } 29  } 30  }); 31  } 32         System.out.println("全部的10個任務已經所有提交。");   //任務都提交了,交由線程池去搞
33         threadPool.shutdown();   //沒有任務後關閉線程 34           //threadPool.shutdownNow(); //還有任務沒有給執行完畢就當即關閉線程 35         
36         //定時器線程池: 3個線程 
37         System.out.println("敵軍還有5秒到達戰場."); 38         Executors.newScheduledThreadPool(3).schedule(new Runnable() { 39  @Override 40             public void run() { 41                 System.out.println("敵軍抵達戰場,碾碎她們。"); 42  } 43             //5秒後執行線程池內run方法
44         }, 5, TimeUnit.SECONDS); 45         //Executors.newScheduledThreadPool(3)scheduleAtFixedRate(command, initialDelay, period, unit) 46         //scheduleAtFixedRate 定時循環執行線程池內方法
47  } 48 }
相關文章
相關標籤/搜索