03.03 二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

6個併發問題引發的血案

1、synchronized的CPU原語級別是如何實現的?


2、一千萬個數,如何高效求和。
3、不用數學庫,求2開平方的值,精確到小數點兒後10位。
4、線程A不斷打印1-10的數字,打印到第5個數字時通知線程B,請完成編碼。
5、下列三種業務,應該如何使用線程池:
高併發、任務執行時間短的業務
併發不高、任務執行時間長的業務
併發高、業務執行時間長的業務
6、你如何來設計12306網站,能夠撐住最高百萬級別TPS(淘寶最高54萬TPS)?

以上6 個併發問題,一個都答不上來?強烈建議來看看這本馬士兵的「多線程與高併發」書籍

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

給大家看看這本書籍的大概內容

目錄:

  • 第一節:線程的基本概念
  • 第二節:volatile與CAS
  • 第三節:Atomic類和線程同步新機制
  • 第四節:LockSupport、淘寶面試題與源碼閱讀方法論
  • 第五節:AQS源碼閱讀與強軟弱虛4種引用以及ThreadLocal原理與源碼
  • 第六節:併發容器
  • 第七節:線程池
  • 第八節:線程池與源碼閱讀
  • 第九節:JMH與Disruptor

第一節:線程的基本概念

線程與高併發大概講六大塊

  • 第一:基本的概念,從什麼是線程開始
  • 第二:JUC同步工具,就是各種同步鎖
  • 第三:同步容器
  • 第四:線程池
  • 第五:高頻面試加分項的一些面試用的東西,包括纖程
  • 第六:Disruptor,不知道有多少同學聽說過這個框架的,這個框架它也是一個MQ框架
  • (Message Queue)叫做消息隊列,消息隊列非常多,後面還會給大家講Kafka、RabbitMQ,
  • Redis等這些都是消息隊列。Disruptor是目前大家公認的在單機環境上效率最高的、性能最快的
  • MQ。
二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

我們先說一下為什麼要講多線程和高併發?

  • 原因是,你想拿到一個更高的薪水,在面試的時候呈現出了兩個方向的現象:
  • 第一個是上天
  • 項目經驗
  • 高併發 緩存 大流量 大數據量的架構設計
  • 第二個是入地
  • 各種基礎算法,各種基礎的數據結構
  • JVM OS 線程 IO等內容
  • 多線程和高併發,就是入地裡面的內容。

基本概念

我們先從線程的基本概念開始,給大家複習一下,不知道有多少同學是基礎不太好,說什麼是線程都不

知道的,如果這樣的話,花時間去補初級內容的課

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?


二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第二節:volatile與CAS

volatile

我們先來看這個volatile的概念,volatile它是什麼意思,現在像大的互聯網企業的面試,基本上volatile

是必會的,有時候他也不會太問,認為你應該會,但是中小企業也就開始問這方面的問題。

我們來看一下這個小程序,寫了一個方法啊,首先定義了一個變量布爾類型等於true,這裡模擬的是一

個服務器的操作,我的值為true你就給我不間斷的運行,什麼時候為false你再停止。 測試new Thread

啟動一個線程,調用m方法,睡了一秒,最後running等於false,運行方法他是不會停止的。 如果你要

把volatile打開,那麼結果就是啟動程序一秒之後他就會m end停止。(volatile就是不停的追蹤這個

值,時刻看什麼時候發生了變化)

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?


二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

CAS

cas號稱是無鎖優化,或者叫自旋。這個名字無所謂,理解它是幹什麼的就行,概念這個東西是人為了

描述問題解決問題而定義出來的,所以怎麼定義不是很重要,重點是在解決問題上

我們通過Atomic類(原子的)。由於某一些特別常見的操作,老是來回的加鎖,加鎖的情況特別多,所

以乾脆java就提供了這些常見的操作這麼一些個類,這些類的內部就自動帶了鎖,當然這些鎖的實現並

不是synchronized重量級鎖,而是CAS的操作來實現的(號稱無鎖)。

我們來舉例幾個簡單的例子,凡是以Atomic開頭的都是用CAS這種操作來保證線程安全的這麼一些個

類。AtomicInteger的意思就是裡面包了一個Int類型,這個int類型的自增 count++ 是線程安全的,還有

拿值等等是線程安全的,由於我們在工作開發中經常性的有那種需求,一個值所有的線程共同訪問它往

上遞增 ,所以jdk專門提供了這樣的一些類。使用方法AtomicInteger如下代碼

<code>**/<code>
<code>* 解決同樣的問題的高效方法,使用AtomXXX類/<code>
<code>* AtomXXX類的本身方法都是原子性的,但不能保證多個方法連續調用都是原子性的/<code>
<code>* @author mashibing/<code>
<code>*//<code>
<code>package com.mashibing.juc.c_018_00_AtomicXXX;/<code>
<code>import java.util.ArrayList;/<code>
<code>import java.util.List;/<code>
<code>import java.util.concurrent.atomic.AtomicInteger;/<code>
<code>好,我們來分許分析,它的內部實現的原理,主要是聊原理,它的用法看看API都會用。這個原理叫/<code>
<code>CAS操作,incrementAndGet() 調用了getAndAddInt/<code>
<code>當然這個也是一個CompareAndSetInt操作/<code>
<code>public class T01_AtomicInteger {/<code>
<code>/*volatile*/ //int count1 = 0;/<code>
<code>AtomicInteger count = new AtomicInteger(0);/<code>
<code>/*synchronized*/ void m() {/<code>
<code>for (int i = 0; i < 10000; i++)/<code>
<code>//if count1.get() < 1000/<code>
<code>count.incrementAndGet(); //count1++/<code>
<code>}/<code>
<code>public static void main(String[] args) {/<code>
<code>T01_AtomicInteger t = new T01_AtomicInteger();/<code>
<code>List<thread> threads = new ArrayList<thread>();/<thread>/<thread>/<code>
<code>for (int i = 0; i < 10; i++) {/<code>
<code>threads.add(new Thread(t::m, "thread-" + i));/<code>
<code>}/<code> 
<code>threads.forEach((o) -> o.start());/<code>
<code>threads.forEach((o) -> {/<code>
<code>try {/<code>
<code>o.join();/<code>
<code>} catch (InterruptedException e) {/<code>
<code>e.printStackTrace();/<code>
<code>}/<code>
<code>});/<code>
<code>System.out.println(t.count);/<code>
<code>}/<code>
<code>}/<code>
二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第三節:Atomic類和線程同步新機制

今天,我們繼續講一個Atomic的問題,然後開始講除synchronized之外的別的鎖。在前面內容我們講

了synchronized、volatile、Atomic和CAS,Atomic我們只是講了一個開頭還沒有講完,今天我們繼

續。

像原來我們寫m++你得加鎖,在多線程訪問的情況下,那現在我們可以用AtomicInteger了,它內部就

已經幫我們實現了原子操作,直接寫 count.incrementAndGet(); //count1++ 這個就相當於count++。原

來我們對count是需要加鎖的,現在就不需要加鎖了。

我們看下面小程序,模擬,我們計一個數,所有的線程都要共同訪問這個數count值,大家知道如果所

有線程都要訪問這個數的時候,如果每個線程給它往上加了10000,你這個時候是需要加鎖的,不加鎖

會出問題。但是,你把它改成AtomicInteger之後就不用在做加鎖的操作了,因為incrementAndGet內

部用了cas操作,直接無鎖的操作往上遞增,有同學可能會講為什麼要用無鎖操作啊,原因是無鎖的操

作效率會更高。

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第四節:LockSupport、淘寶面試題與源碼閱讀方法論

首先我們簡單回顧一下前面三節課講的內容,分別有線程的基本概念、synchronized、volatile、

AtomicXXX、各種JUC同步框架(ReentrantLock、CountDownLatch、CyclicBarrier、Phaser、

ReadWriteLock-StampedLock、Semaphore、Exchanger、LockSupport),其中synchornized重點講

了一下,包括有synchornized的底層實現原理、鎖升級的概念(四種狀態:無鎖、偏向鎖、輕量級鎖、

重量級鎖),volatile我們講了可見性和禁止指令重排序如何實現。

synchronized和ReentrantLock的不同?

synchronized:系統自帶、系統自動加鎖,自動解鎖、不可以出現多個不同的等待隊列、默認進行

四種鎖狀態的升級

ReentrantLock:需要手動枷鎖,手動解鎖、可以出現多個不同的等待隊列、CIS的實現

本章我們補一個小漏洞,它叫LockSupport,然後我們分析兩道面試題,緊接著我會教大家閱讀源碼的

技巧,源碼層出不窮,生生不息,掌握了源碼的閱讀技巧,大家培養出了閱讀源碼興趣的時候,之後好

多代碼,你需要自己去摳,摳出來才是你自己的,最後我們會分析AQS源碼,以上是我們本章主講的內

容概述。

LockSupport

我們會以幾個小程序為案例,展開對LockSupport的講解,在以前我們要阻塞和喚醒某一個具體的線程

有很多限制比如:

1、因為wait()方法需要釋放鎖,所以必須在synchronized中使用,否則會拋出異常

IllegalMonitorStateException

2、notify()方法也必須在synchronized中使用,並且應該指定對象

3、synchronized()、wait()、notify()對象必須一致,一個synchronized()代碼塊中只能有一個線程調

用wait()或notify()

以上諸多限制,體現出了很多的不足,所以LockSupport的好處就體現出來了。

在JDK1.6中的java.util.concurrent的子包locks中引了LockSupport這個API,LockSupport是一個比較

底層的工具類,用來創建鎖和其他同步工具類的基本線程阻塞原語。java鎖和同步器框架的核心 AQS:

AbstractQueuedSynchronizer,就是通過調用 LockSupport .park()和 LockSupport .unpark()的方

法,來實現線程的阻塞和喚醒的。我們先來看一個小程序:

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

後續的內容給大家大概截個圖,由於內容太多了

第五節:AQS源碼閱讀與強軟弱虛4種引用以及ThreadLocal原理與源碼

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第六節:併發容器

今天是第六天了,這節課本來想上一個大而全的課,後來發現這個實在目標太大了,大而全的概念就是

上節課講到的那張容器圖中的每一個都講的非常的細緻,然後去談他們的源碼。但是如果這麼講的話我

們高併發的課就講不完了,所以也彆著急,後面單獨開一門課來講集合,集合的發展歷程,現在為什麼

講這個併發容器呢,主要是為了線程池做準備,線程池裡有一個參數就是用併發容器來做你工作任務的

容器。

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?


二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第七節:線程池

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第八節:線程池與源碼閱讀

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

第九節:JMH與Disruptor

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

如何獲取?

轉發這篇文章,關注我,私信回覆“馬士兵”即可獲取電子書籍,以上 spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構

如何私信?

關注我後,在手機,點進我的主頁,主頁上方右上角有個私信,點擊私信,如何回覆關鍵字“馬士兵”即可

粉絲福利:

以上6 個併發問題,一個都答不上來?強烈建議!!拿出4個小時的時間,參加一次馬士兵老師的《多線程與高併發》訓練營。

二十年架構師「馬士兵大牛」告訴你:多線程與高併發應該怎麼學?

關注我,私信“馬士兵”免費參與


分享到:


相關文章: