從學代碼到跑路

最近給組裏的小夥伴作了一次培訓,分享了一些編程的基礎和自我學習編程的方法。感受對你們可能有用,裏面頗有很面試常常問到的基礎相關的東西,想分享給大夥。java

計算機基礎篇

首先看三段代碼,分別爲JS代碼、C#代碼和Java代碼。有:局部變量、全局變量,值類型和引用類型,靜態和常量、線程(JS沒有)。node

// 定義了一個Person類
function Person(id,name,age){
  this.id = id;
  this.name = name;
  this.age = age;
}
function test(){
  // 局部變量
  let id = 0;
  console.log(id);
}
// 全局變量
var person = new Person(100,'梁先生',25);
test();
複製代碼
// 定義了一個Person類
public class Person {  
  // 常量
  public const string CodeTest = "梁先生"// 靜態變量
  public static int Code = 0; 
  // 私有變量
  private int testId;
  public void add(){
    // 局部變量
    int temp = 0;
    testId++;    
  }
}

// 線程類
public class Count implements Runnable{
  Person person;
  public Count(Person person){
      this.person = person;
  }    
  @Override
  public void run(){
     person.add();
  }
}

var person = new Person(100,'梁先生',25);
// 多線程的問題
int threadCount = 100;
for(int i = 0; i<threadCount;i++){
    ThreadMsDeal = new Thread(new Count(person));
	ThreadMsDeal.Start();
}
複製代碼
// 定義了一個Person類
public class Person{
  // 常量
  public const string CodeTest = "梁先生";
  // 靜態變量
  public static int Code = 0; 
    
  // 定義了一個私有變量
  private testId = 0;
  public Person(id,name,age){
    this.id = id;
    this.name = name;
    this.age = age;
  }
    
  public int id {get;set;}
  public string name{get;set;}
  public int age{get;set;}
    
  public void test(){
    // 局部變量
    int temp = 0;
    testId++;    
  }
}

var person = new Person(100,'梁先生',25);
// 多線程的問題
int threadCount = 100;
for(int i = 0; i<threadCount;i++){
    ThreadMsDeal = new Thread(new ThreadStart(test));
	ThreadMsDeal.Start();
}
複製代碼

上面代碼中的數據類型都能在下方的圖找到對應。 git

數據類型

怎麼分配的呢

JVM和CLR和很相似,使用JVM來講明 github

JVM

  • new 的引用類型的值存在堆中。
  • 普通值類型的如int啥的放在棧中。
  • const的值是在編譯期間肯定的,所以只能在聲明時經過常量表達式指定其值。
  • static限定,意味着「無論類的對象被建立多少次,都只有一個實例」  。
  • 本地方法棧:虛擬機使用到的Native 方法服務。
  • 常量和靜態變量都是放在方法區裏面的,這個區域也對全部線程共享。

js的V8虛擬機和上面兩種有點像,可是又很不相同:JavaScript中全部的數據都是存放在堆內存中,爲了基本數據類型和引用數據類型的理解區分開來。面試

V8
文字總結內存

值類型和引用類型 算法

值類型的內存分配

引用類型的內存分配

Q:爲何阿里巴巴Java開發手冊不建議在for循環中使用「+」進行字符串拼接? 數據庫

String

A:String是一個對象,且對象一旦被建立就是固定不變的了,對String對象的任何改變都不影響到原對象,全部一直在建立和銷燬對象,改變指針的指向,浪費內存和性能。咱們可使用StringBuilder和StringBuffer,他們是可變的。編程

GC垃圾回收c#

垃圾回收

  • 若是不進行垃圾回收,內存早晚都會被消耗空
  • 內存溢出:就是你要求分配的內存超出了系統能給你的,系統不能知足需求,因而產生溢出
  • 內存泄漏:是指你向系統申請分配內存進行使用(new),但是使用完了之後卻不回收

垃圾回收的幾種方式 設計模式

標記清除:後會產生大量不連續的內存碎片

標記-整理算法:GC暫停的時間會增加,須要將全部的對象都拷貝到一個新的地方,並更新它們的地址

複製算法:須要一塊能容納下全部存活對象的額外的內存空間,可一次性分配的最大內存縮小了一半

跳過

**GC調優:**不少次面試的時候有問道,gc垃圾回收的調優,你又瞭解嘛?

  1. 不要顯式調用GC的回收函數,好比:Java中的 System.gc()、C#中的析構(2次回收)
  2. 儘可能減小臨時對象的使用(不使用的變量就給刪掉)
  3. 對象不用時最好顯式置爲Null
  4. 不用大量的String來字符串拼接
  5. 能用基本類型如Int,Long,就不用Integer,Long對象
  6. 儘可能少用靜態對象變量,由於靜態變量只有在程序結束時才釋放
  7. 分散對象建立或刪除的時間,好比避免:new 類[10000]

線程不安全

線程不安全

不安全

圖

線程不安全:就是不提供數據訪問保護,有可能出現多個線程前後更改數據形成所獲得的數據是髒數據。

Q: i++是線程安全嗎? A: 是不安全的

jvm的線程模型

每一個線程都有本身的工做內存,每一個線程須要對共享變量操做時必須先把共享變量從主內存 load 到本身的工做內存,等完成對共享變量的操做時再 save 到主內存。好比上面的i,是先拷貝到線程中的,而後作完++之後,不是很及時的刷新到主存。

問題就出在這了,若是一個線程運算完後還沒刷到主內存,此時這個共享變量的值被另一個線程從主內存讀取到了,這個時候讀取的數據就是髒數據了,它會覆蓋其餘線程計算完的值。

線程安全必要條件

必要條件

原子性:跟數據庫事務的原子性概念差很少,即一個操做(有可能包含有多個子操做) 要麼所有執行(生效),要麼所有都不執行(都不生效)。

可見性:當多個線程併發訪問共享變量時,一個線程對共享變量的修改, 其它線程可以當即看到。可見性問題是好多人忽略或者理解錯誤的一點。

順序性:是程序執行的順序按照代碼的前後順序執行。

解決辦法

原子性解決:保證操做原子性的工具是鎖和同步方法(或者同步代碼塊)。使用鎖,能夠保證同一時間只有一個線程能拿到鎖,也就保證了同一時間只有一個線程能執行申請鎖和釋放鎖之間的代碼。 Java中的synchronized、c#中的lock

可見性解決:volatile關鍵字來保證可見性。當使用volatile修飾某個變量時,它會保證對該變量的修改會當即被更新到內存中,所以其它線程須要讀取該值時必須從主內存中讀取,從而獲得最新的值。

高併發,目前比較流行的有兩種,一種爲多線程的方式(java中後臺就是這樣的),一種是事件驅動,異步IO(node中是這樣的)。

高併發-多線程

多線程

線程的調度

線程的在操做系統的調度中,某個時刻,只能將資源讓給一個線程。而線程的上下文的切換,會有很大的消耗。

高併發-異步IO

異步IO

事件隊列

只有一個線程,沒有上下文的切換消耗,可是隻有一個線程幹活。

選擇場景若是 IO時間多,那異步IO效率高,選擇場景若是 計算時間多,那同步IO效率高。Nginx 和 Node就是基於這種模式

經常使用的數據結構

  • 數組(數組不要定義太長,由於須要連續的空間。不夠的時候會引發GC)
  • 棧(遞歸的時候利用的是棧)
  • 隊列(日誌的讀寫分離)
  • 鏈表
  • 樹 (菜單遞歸建樹、數據庫索引)
  • 哈希表(查詢數據快,只須要一次哦)

時間複雜度

時間複雜度

這個方法須要 (n + 1 + n + 1) = 2n + 2 次運算。咱們通常會把係數和尾巴去掉,由於在n趨近無窮大的時候,係數和尾巴都不咋起做用,差不了多少。故:時間複雜度爲:O(n)

void Func(int n) {
    for(int i = 0; i < n; i++) {         
        for(int j = 0; j < n; j++) {       
            printf("Hello, World!\n");      
        }
    }
}
複製代碼

時間複雜度爲:O(n × n × 1),即 O(n^2)。:

數據結構的時間複雜度

數據結構的時間複雜度

時間複雜度的圖像,根據本身的編碼狀況選擇對應的數據結構

時間複雜度的圖表

你們能夠對比一下,在x軸趨於無窮大時,x爲數據量,而O(1)和log(n)的y值還只是1或者很小很小,y爲查詢的操做的次數。因此你們能夠選擇必定的數據結構來優化本身的代碼


面向對象篇

在編碼的時候去理解和運用一下三個特徵。由於培訓例子是舉的工做中的例子,不咋好拿代碼出來說解。在咱們發現有相同的代碼的時候,咱們是能夠抽象出來的。還有一個是:對接口編程,而不是對實現編程。

面向對象

五大原則也是須要必定的編碼去支撐,而後才能本身的理解

五大原則

還有經常使用的設計模式,這個也是很重要的,須要掌握經常使用的,由於時間問題,不在這裏講解。

總結篇

這個是我的總結,和語言無關,和框架無關。我的仍是以爲基礎仍是很重要的,若是你懂基礎,在代碼優化,和出問題的時候去排查,站的角度是不同的。

可能涉及到的書或者知識點比較多,可是沒有必要全看完整的東西 ,只須要掌握基礎,經常使用的知識點便可。不經常使用的東西,或者都不會涉及到的東西就不用看。

不少如代碼重構,優化,是能夠一直貫穿在整個圖中的。

編程學習

下方是是我的的一些學習方法和常常看到一些知識點的出處。

學習方法

但願能幫助到你們,謝謝!

github.com/liangwei010… 能夠的話,給個星星哦!

相關文章
相關標籤/搜索