快速鳥瞰併發編程, 嘔心瀝血整理的架構技術【3】

做者:享學課堂James老師java

轉載請聲明出處!程序員

接着第1, 2篇後,咱們繼續來跟進一下併發編程的其它內容,以下:編程

第9節 java.util.concurrent包

線程池

線程池的核心接口是 ExecutorServicejava.util.concurrent還提供了一個靜態工廠類 Executors,其中包含用於建立配置線程池的工廠方法。安全

其實 靜態工廠方法以下bash

注意:數據結構

調整線程池大小時,大小是根據你的計算機中的邏輯核心數而定的。這個大小能夠經過調用Runtime.getRuntime().availableProcessors()方法得到該值。多線程

任務隨着 ExecutorService#submitExecutorService#invokeAll或者提交, ExecutorService#invokeAny對於不一樣類型的任務具備多個重載。併發

其實 功能接口以下ide

Future

Future是對於具體的Runnable任務或Callable任務的執行結果進行取消、查詢是否完成、獲取結果。必要時能夠經過get方法獲取執行結果,該方法會阻塞直到任務返回結果。高併發

ExecutorService使用 Future做爲返回類型。

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<String> future = executorService.submit(() -> "結果");
try {
	String result = future.get(1L, TimeUnit.SECONDS);
	System.out.println("結果爲 '" + result + "'.");
}
catch (InterruptedException e) {
	Thread.currentThread().interrupt();
	throw  new  RuntimeException(e);
}
catch (ExecutionException e) {
	throw  new  RuntimeException(e.getCause());
}
catch (TimeoutException e) {
	throw  new  RuntimeException(e);
}
assert future.isDone();
複製代碼

ReentrantLock鎖

java.util.concurrent.locks軟件包括了常常使用到的 Lock接口。ReentrantLock類其實也實現了 synchronized關鍵字的功能,還提供了其它功能,例如獲取有關鎖的狀態,非阻塞 tryLock()和可中斷鎖的信息。使用顯式 ReentrantLock的示例以下:

class  JamesCounter {
	private  final  Lock lock = new  ReentrantLock();
	private  int value;
	int increment() {
		lock.lock();
		try {
			return ++value;
		}
		finally {
			lock.unlock();
		}
	}
}
複製代碼

ReadWriteLock讀寫鎖

java.util.concurrent.locks還包含一個 ReadWriteLock接口( ReentrantReadWriteLock實現),讀寫鎖,一般容許多個併發讀取,但只容許一個寫入。

class  JamesStatistic {
	private  final  ReadWriteLock lock = new  ReentrantReadWriteLock();
	private  int value;
	void increment() {
		lock.writeLock().lock();
		try {
			value++;
		}
		finally {
			lock.writeLock().unlock();
		}
	}
	int current() {
		lock.readLock().lock();
		try {
			return value;
		}
		finally {
			lock.readLock().unlock();
		}
	}
}
複製代碼

CountDownLatch工具

CountDownLatch主要用過計數,好比開項目大會,項目經理在會議室門口,有5個程序員A B C D E(至關於5個線程)分別來會議室開會,項目經理手寫拿了一份會議人員名單,程序員A進入了會議室後,項目經理把A名單打個勾表示來了(至關於建立了線程A),B進會議室後,在名單上把B也打勾(至關於建立了線程B),但請注意,人沒到齊, A,B程序員只能在座位上等待(線程全在等待阻塞中),還不能開會,等5個程序員都到齊了,纔開會(5個線程同時被喚醒,開始工做)。

@SpringBootTest(classes = TripApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public  class  JamesTestInvokeRemote {
	private  static  final  int THREADS = 200;//200線程模擬用戶提交併發
	RestTemplate rest = new  RestTemplate();
	private  final  String url = "http://127.0.0.1:8090/buyTicket?idcard=123456";
	private  static  CountDownLatch cdl = new  CountDownLatch(THREADS);//200
	@Test
	public  void  TestInvoke() throws  InterruptedException {
		for (int i = 0; i < THREADS; i++){
			new  Thread(new  TicketRequest()).start();
			//模擬5個程序員陸陸續續進門
		}
	}
	public  class  JamesTicketRequest  implements  Runnable{
		@Override
		public  void run() {
			cdl.countDown();
			//項目經理的名單上勾掉一個,其實就是減1
			try {
				cdl.await();
				//全部程序員末到位前,都在椅子上等待(全部線程等待),直到                                         //cdl.countDown()減爲0時喚醒
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			//5個線程同時(併發請求)執行業務邏輯`
			String str = rest.getForEntity(url, String.class).getBody();
			//併發同時請求
			System.out.println(str);
		}
	}
}
複製代碼

併發知識彙總

集合線程安全的最簡單方法就是使用 Collections#synchronized鎖定方法。因爲此解決方案在高併發場景下表現不佳,所以 java.util.concurrent提供了針對併發使用進行了優化的各類數據結構。

List集合

Maps集合

Set集合

Queue隊列

隊列實際上是充當了「生產者」和「消費者」之間的管道。換句話來講就是個「先進先出」(FIFO)順序而已。BlockingQueue接口擴展 Queue,提供永久阻塞或按指定的時間段進行阻塞的方法,它的等待條件會因另外一個線程的操做而發生改變。

花了幾天時間總算寫完了,但願對你們有幫助。看完這篇,你們至少要對多線程的一些經常使用工具類要有所瞭解。

關注我,還有更多技術乾貨分享~

相關文章
相關標籤/搜索