Java 源碼刨析 – 線程的狀態有哪些?它是如何工作的?

線程(Thread)是併發編程的基礎,也是程序執行的最小單元,它依託進程而存在

一個進程中可以包含多個線程,多線程可以共享一塊內存空間和一組系統資源,因此線程之間的切換更加節省資源、更加輕量化,也因此被稱為輕量級的進程。

   

線程的狀態在 JDK 1.5 之後以枚舉的方式被定義在 Thread 的源碼中,它總共包含以下 6 個狀態:

NEW新建狀態,線程被創建出來,但尚未啟動時的線程狀態;

RUNNABLE就緒狀態,表示可以運行的線程狀態,它可能正在運行,或者是在排隊等待操作系統給它分配 CPU 資源;

BLOCKED阻塞等待鎖的線程狀態,表示處於阻塞狀態的線程正在等待監視器鎖,比如等待執行 synchronized 代碼塊或者使用 synchronized 標記的方法;

WAITING等待狀態,一個處於等待狀態的線程正在等待另一個線程執行某個特定的動作,比如,一個線程調用了 Object.wait() 方法,那它就在等待另一個線程調用 Object.notify() Object.notifyAll() 方法;

TIMED_WAITING計時等待狀態,和等待狀態(WAITING)類似,它只是多了超時時間,比如調用了有超時時間設置的方法 Object.wait(long timeout) Thread.join(long timeout) 等這些方法時,它才會進入此狀態;

TERMINATED終止狀態,表示線程已經執行完成。

線程狀態的源代碼如下:

public enum State {

    /**

     * 新建狀態,線程被創建出來,但尚未啟動時的線程狀態

     */

    NEW,

   

    /**

     * 就緒狀態,表示可以運行的線程狀態,但它在排隊等待來自操作系統的 CPU 資源

     */

    RUNNABLE,

   

    /**

     * 阻塞等待鎖的線程狀態,表示正在處於阻塞狀態的線程

     * 正在等待監視器鎖,比如等待執行 synchronized 代碼塊或者

     * 使用 synchronized 標記的方法

     */

    BLOCKED,

   

    /**

     * 等待狀態,一個處於等待狀態的線程正在等待另一個線程執行某個特定的動作。

     * 例如,一個線程調用了 Object.wait() 它在等待另一個線程調用

     * Object.notify() 或 Object.notifyAll()

     */

    WAITING,

   

    /**

     * 計時等待狀態,和等待狀態 (WAITING) 類似,只是多了超時時間,比如

     * 調用了有超時時間設置的方法 Object.wait(long timeout) 和 

     * Thread.join(long timeout) 就會進入此狀態

     */

    TIMED_WAITING,

   

    /**

     * 終止狀態,表示線程已經執行完成

     */

}

   

線程的工作模式是,首先先要創建線程並指定線程需要執行的業務方法,然後再調用線程的 start() 方法,此時線程就從 NEW(新建)狀態變成了 RUNNABLE(就緒)狀態;

然後線程會判斷要執行的方法中有沒有 synchronized 同步代碼塊,如果有並且其他線程也在使用此鎖,那麼線程就會變為 BLOCKED(阻塞等待)狀態,當其他線程使用完此鎖之後,線程會繼續執行剩餘的方法。

   

當遇到 Object.wait() Thread.join() 方法時,線程會變為 WAITING(等待狀態)狀態;

如果是帶了超時時間的等待方法,那麼線程會進入 TIMED_WAITING(計時等待)狀態;

當有其他線程執行了 notify() notifyAll() 方法之後,線程被喚醒繼續執行剩餘的業務方法,直到方法執行完成為止,此時整個線程的流程就執行完了,執行流程如下圖所示:

BLOCKED WAITING 的區別】

雖然 BLOCKED WAITING 都有等待的含義,但二者有着本質的區別。

首先它們狀態形成的調用方法不同

其次 BLOCKED 可以理解為當前線程還處於活躍狀態,只是在阻塞等待其他線程使用完某個鎖資源

WAITING 則是因為自身調用 Object.wait() 或着是 Thread.join() 又或者是 LockSupport.park() 而進入等待狀態,只能等待其他線程執行某個特定的動作才能被繼續喚醒。

比如當線程因為調用了 Object.wait() 而進入 WAITING 狀態之後,則需要等待另一個線程執行 Object.notify() Object.notifyAll() 才能被喚醒。

   

start() run() 的區別】

首先從 Thread 源碼來看,start() 方法屬於 Thread 自身的方法,並且使用了 synchronized 來保證線程安全,源碼如下:

public synchronized void start() {

    // 狀態驗證,不等於 NEW 的狀態會拋出異常

    if (threadStatus != 0)

        throw new IllegalThreadStateException();

    // 通知線程組,此線程即將啟動

   

    group.add(this);

    boolean started = false;

    try {

        start0();

        started = true;

    } finally {

        try {

            if (!started) {

                group.threadStartFailed(this);

            }

        } catch (Throwable ignore) {

            // 不處理任何異常,如果 start0 拋出異常,則它將被傳遞到調用堆棧上

        }

    }

}

   

run() 方法為 Runnable 的抽象方法,必須由調用類重寫此方法,重寫的 run() 方法其實就是此線程要執行的業務方法,源碼如下:

public class Thread implements Runnable {

 // 忽略其他方法……

  private Runnable target;

  @Override

  public void run() {

      if (target != null) {

          target.run();

      }

  }

}

@FunctionalInterface

public interface Runnable {

    public abstract void run();

}

   

從執行的效果來說,start() 方法可以開啟多線程,讓線程從 NEW 狀態轉換成 RUNNABLE 狀態,而 run() 方法只是一個普通的方法。

   

其次,它們可調用的次數不同,start() 方法不能被多次調用,否則會拋出 java.lang.IllegalStateException;而 run() 方法可以進行多次調用,因為它只是一個普通的方法而已。

   

【線程優先級】

Thread 源碼中和線程優先級相關的屬性有 3 個:

// 線程可以擁有的最小優先級

public final static int MIN_PRIORITY = 1;

   

// 線程默認優先級

public final static int NORM_PRIORITY = 5;

   

// 線程可以擁有的最大優先級

public final static int MAX_PRIORITY = 10

   

線程的優先級可以理解為線程搶佔 CPU 時間片的概率,優先級越高的線程優先執行的概率就越大,但並不能保證優先級高的線程一定先執行。

   

在程序中我們可以通過 Thread.setPriority() 來設置優先級,setPriority() 源碼如下:

public final void setPriority(int newPriority) {

    ThreadGroup g;

    checkAccess();

    // 先驗證優先級的合理性

    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {

        throw new IllegalArgumentException();

    }

    if((g = getThreadGroup()) != null) {

        // 優先級如果超過線程組的最高優先級,則把優先級設置為線程組的最高優先級

        if (newPriority > g.getMaxPriority()) {

            newPriority = g.getMaxPriority();

        }

        setPriority0(priority = newPriority);

    }

}

   

【線程的常用方法】

線程的常用方法有以下幾個。

   

join()

一個線程中調用 other.join() ,這時候當前線程會讓出執行權給 other 線程,直到 other 線程執行完或者過了超時時間之後再繼續執行當前線程,join() 源碼如下:

public final synchronized void join(long millis)

throws InterruptedException {

    long base = System.currentTimeMillis();

    long now = 0;

    // 超時時間不能小於 0

    if (millis < 0) {

        throw new IllegalArgumentException(“timeout value is negative”);

    }

    // 等於 0 表示無限等待,直到線程執行完為之

    if (millis == 0) {

        // 判斷子線程 (其他線程) 為活躍線程,則一直等待

        while (isAlive()) {

            wait(0);

        }

    } else {

        // 循環判斷

        while (isAlive()) {

            long delay = millis  now;

            if (delay <= 0) {

                break;

            }

            wait(delay);

            now = System.currentTimeMillis()  base;

        }

    }

}

   

從源碼中可以看出 join() 方法底層還是通過 wait() 方法來實現的。

   

例如,在未使用 join() 時,代碼如下:

public class ThreadExample {

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(() -> {

            for (int i = 1; i < 6; i++) {

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println(子線程睡眠: + i + 秒。);

            }

        });

        thread.start(); // 開啟線程

        // 主線程執行

        for (int i = 1; i < 4; i++) {

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(主線程睡眠: + i + 秒。);

        }

    }

}

程序執行結果為:

複製主線程睡眠:1秒。

子線程睡眠:1秒。

主線程睡眠:2秒。

子線程睡眠:2秒。

主線程睡眠:3秒。

子線程睡眠:3秒。

子線程睡眠:4秒。

子線程睡眠:5秒。

   

從結果可以看出,在未使用 join() 時主子線程會交替執行。

   

然後我們再把 join() 方法加入到代碼中,代碼如下:

public class ThreadExample {

    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(() -> {

            for (int i = 1; i < 6; i++) {

                try {

                    Thread.sleep(1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

                System.out.println(子線程睡眠: + i + 秒。);

            }

        });

        thread.start(); // 開啟線程

        thread.join(2000); // 等待子線程先執行 2 秒鐘

        // 主線程執行

        for (int i = 1; i < 4; i++) {

            try {

                Thread.sleep(1000);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println(主線程睡眠: + i + 秒。);

        }

    }

}

程序執行結果為:

   

複製子線程睡眠:1秒。

子線程睡眠:2秒。

主線程睡眠:1秒。 

// thread.join(2000); 等待 2 秒之後,主線程和子線程再交替執行

子線程睡眠:3秒。

主線程睡眠:2秒。

子線程睡眠:4秒。

子線程睡眠:5秒。

主線程睡眠:3秒。

從執行結果可以看出,添加 join() 方法之後,主線程會先等子線程執行 2 秒之後才繼續執行。

   

yield()

Thread 的源碼可以知道 yield() 為本地方法,也就是說 yield() 是由 C C++ 實現的,源碼如下:

public static native void yield();

   

yield() 方法表示給線程調度器一個當前線程願意出讓 CPU 使用權的暗示,但是線程調度器可能會忽略這個暗示。

   

比如我們執行這段包含了 yield() 方法的代碼,如下所示:

public static void main(String[] args) throws InterruptedException {

    Runnable runnable = new Runnable() {

        @Override

        public void run() {

            for (int i = 0; i < 10; i++) {

                System.out.println(線程: +

                        Thread.currentThread().getName() +  I + i);

                if (i == 5) {

                    Thread.yield();

                }

            }

        }

    };

    Thread t1 = new Thread(runnable, “T1”);

    Thread t2 = new Thread(runnable, “T2”);

    t1.start();

    t2.start();

}

   

當我們把這段代碼執行多次之後會發現,每次執行的結果都不相同,這是因為 yield() 執行非常不穩定,線程調度器不一定會採納 yield() 出讓 CPU 使用權的建議,從而導致了這樣的結果。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

聚甘新

一文梳理JavaScript 事件循環(Event Loop)

事件循環(Event Loop),是每個JS開發者都會接觸到的概念,但是剛接觸時可能會存在各種疑惑。

眾所周知,JS是單線程的,即同一時間只能運行一個任務。一般情況下這不會引發問題,但是如果我們有一個耗時較多的任務,我們必須等該任務執行完畢才能進入下一個任務,然而等待的這段時間常常讓我們無法忍受,因為我們這段時間什麼都不能做,包括頁面也是鎖死狀態。

好在,時代在進步,瀏覽器向我們提供了JS引擎不具備的特性:Web API。Web API包括DOM API、定時器、HTTP請求等特性,可以幫助我們實現異步、非阻塞的行為。我們可以通過異步執行任務的方法來解決單線程的弊端,事件循環為此而生

提問QAQ:為什麼JavaScript是單線程的?

多個線程表示您可以同時獨立執行程序的多個部分。確定一種語言是單線程還是多線程的最簡單方法是看它擁有有多少個調用堆棧。JS 只有一個,所以它是單線程語言。

將JS設計為單線程是由其用途運行環境等因素決定的,作為瀏覽器腳本語言,JS的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很複雜的同步問題。同時,單線程執行效率高。

1. Event Loop舊印象

大家熟悉的關於事件循環的機制說法大概是:主進程執行完了之後,每次從任務隊列里取一個任務執行。如圖所示,所有的任務分為同步任務和異步任務,同步任務直接進入任務隊列–>主程序執行;異步任務則會掛起,等待其有返回值時進入任務隊列從而被主程序執行。異步任務會通過任務隊列的機制(先進先出的機制)來進行協調。具體如圖所示:

同步和異步任務分別進入不同的執行環境,同步的進入主線程,即主執行棧,異步的進入任務隊列。主線程內的任務執行完畢為空,會去任務隊列讀取對應的任務,推入主線程執行。 上述過程的不斷重複就是我們所熟悉的Event Loop (事件循環)。但是promise出現之後,這個說法就不太準確了

2. Event Loop 後印象

2.1 理論

這裏首先用一張圖展示JavaScript的事件循環:

直接看這張圖,可能黑人問號已經出現在同學的腦海。。。

這裏將task分為兩大類,分別是macroTask(宏任務)和microTask(微任務).一次事件循環:先運行macroTask隊列中的一個,然後運行microTask隊列中的所有任務。接着開始下一次循環(只是針對macroTask和microTask,一次完整的事件循環會比這個複雜的多)。

那什麼是macroTask?什麼是microTask呢?

JavaScript引擎把我們的所有任務分門別類,一部分歸為macroTask,另外一部分歸為microTack,下面是類別劃分:

macroTask:

  • setTimeout
  • setInterval
  • setImmediate
  • requestAnimationFrame
  • I/O
  • UI rendering

microTask:

  • process.nextTick
  • Promise
  • Object.observe
  • MutationObserver

我們所熟悉的定時器就屬於macroTask,僅僅了解macroTask的機制還是不夠的。為直觀感受兩種隊列的區別,下面上代碼進行實踐感知。

2.2 實踐

以setTimeout、process.nextTick、promise為例直觀感受下兩種任務隊列的運行方式。

console.log('main1');

process.nextTick(function() {
    console.log('process.nextTick1');
});

setTimeout(function() {
    console.log('setTimeout');
    process.nextTick(function() {
        console.log('process.nextTick2');
    });
}, 0);

new Promise(function(resolve, reject) {
    console.log('promise');
    resolve();
}).then(function() {
    console.log('promise then');
});

console.log('main2');

別著急看答案,先以上面的理論自己想想,運行結果會是啥?

最終結果是這樣的:

main1
promise
main2
process.nextTick1
promise then

// 第二次事件循環
setTimeout
process.nextTick2

process.nextTick 和 promise then在 setTimeout 前面輸出,已經證明了macroTask和microTask的執行順序。但是有一點必須要指出的是。上面的圖容易給人一個錯覺,就是主進程的代碼執行之後,會先調用macroTask,再調用microTask,這樣在第一個循環里一定是macroTask在前,microTask在後。

但是最終的實踐證明:在第一個循環里,process.nextTick1和promise then這兩個microTask是在setTimeout這個macroTask里之前輸出的,這是因為Promises/A+規範規定主進程的代碼也屬於macroTask。

主進程這個macroTask(也就是main1、promise和main2)執行完了,自然會去執行process.nextTick1和promise then這兩個microTask。這是第一個循環。之後的setTimeout和process.nextTick2屬於第二個循環

別看上面那段代碼好像特別繞,把原理弄清楚了,都一樣 ~

requestAnimationFrame、Object.observe(已廢棄) 和 MutationObserver這三個任務的運行機制大家可以從上面看到,不同的只是具體用法不同。重點說下UI rendering。在HTML規範:event-loop-processing-model里敘述了一次事件循環的處理過程,在處理了macroTask和microTask之後,會進行一次Update the rendering,其中細節比較多,總的來說會進行一次UI的重新渲染。

3. 小結

總而言之,記住一次事件循環:先運行macroTask隊列中的一個,然後運行microTask隊列中的所有任務。接着開始下一次循環。

參考文獻:

  • 總是一知半解的Event Loop
  • 深入理解事件循環機制
  • JavaScript運行機制

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

聚甘新

Tesla台灣旗艦店開幕,Model S 2017年在台上市

不論是在汽車、能源還是科技界,不論發生什麼事情都在大眾目光焦點的特斯拉 (Tesla),既三月份成立臺灣分公司之後有更進一步的動作。特斯拉的臺北旗艦店在今日 (9 月1 日) 在臺北信義商圈開幕,有興趣的人可以到店體驗特斯拉房車Model S,並且預約試駕和進一步訂購,預計明年 (2017) 第一季交車。

特斯拉看中臺灣在科技產業的樞鈕地位,因此在亞太區暨中國、香港、澳門、澳洲之後,選擇臺灣,成為特斯拉全球第25 個設立的國家。而在信義商圈新光三越A11 的台灣旗艦店,則是第204 家店。選在臺灣的首善之都臺北,則是著眼信義商圈是臺北最繁盛的購物商圈,對新事物的接受度高,因此選在新光三越A11 設旗艦店,並且還跟新光三越合作,在百貨公司的地下停車場設立充電站。

電動車要能方便,必須有足夠的的充電站。Tesla香港、澳門及台灣地區區域總監范菁怡表示,目前除了設在車主自家的居家充電站之外,還會與百貨商場、飯店合作,在停車場設置目的地充電站。未來特斯拉也將在高速公路沿線設置超級充電站,服務需長距離駕駛的特斯拉車子。

由於特斯拉代表新一代的潔淨能源運用型式,對於提高都市運輸效率和降低污染有顯著效果,因此除了特斯拉的代表和合作的百貨公司代表以外,臺北市政府也由副市長林欽榮出席。另外還有負責招商相關事務的行政院全球招商及攬才聯合服務中心何怡明執行長,以及經濟部工業局黃裕峰副組長出席。林欽榮致詞時表示,臺北市仍然要繼續推動共享汽車,U-Car 計畫。

儘管目前在臺灣還只能預購特斯拉的Model S 房車車型,但是特斯拉計畫在臺引進平價車款Model 3,定價3 萬5,000 美元,預計明年引進,目前正在商品檢驗階段。

「電動車勢必是未來交通方式的主流,Tesla 一直期望扮演推動永續能源應用的角色。我們樂見台灣對環保、綠色能源的高接受度,也很高興Tesla 能成為這波改革中的一股力量。」Tesla 全球副總裁暨亞太區總裁任宇翔表示:「臺灣特殊的地理和城市發展環境,以及政府對於相關政策和補助的支持,讓Tesla 清楚看到電動車在臺灣的發展性。臺灣廠商不僅是Tesla供應鏈的合作夥伴,更在電動車的推廣上佔有重要地位。隨著Tesla 電動車在台上市與充電站的逐步擴充,Tesla 對臺灣市場的發展潛力深具信心,除了希望對合作夥伴和經濟發展帶來正面影響,更期望與臺灣一起開創電動車的新篇章。」

特斯拉之後將在臺灣設立客服,還有佈建充電網路,當特斯拉的Model S 在臺灣的道路奔馳時,超級充電站和目的地充電站在商圈、景點等地方,形成足夠的網狀分佈,維持特斯拉的輪胎不停轉動。全球有超過9,000 萬臺汽車,目前只有不到0.2% 的汽車是電動車,特斯拉推動電動車,還可以有很大的施力空間。

(首圖:設在新光三越信義A11 地下4 樓停車場的特斯拉目的地充電站,在2017 年特斯拉車子在臺灣道路奔馳之際,這類設在購物商場的充電站將會越來越多。來源:科技新報)

(本文授權轉載自《》──〈〉)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

聚甘新

過來人告訴你,去工作前最好還是學學Git

前言

只有光頭才能變強。

文本已收錄至我的GitHub精選文章,歡迎Star:https://github.com/ZhongFuCheng3y/3y

之前遇到過很多同學私信問我:「三歪,我馬上要實習了,我要在實習前學些什麼做準備啊?」

三歪在實習之前也同樣問過自己當時的部門老大。

如果再給我一次機會,我會先去花點時間去學學Git

Git我相信大家對它應該不陌生吧?但凡用過GitHub的同學應該多多少少都會了解一下Git

不知道當時大家學Git的時候是看哪個教程的,我看的是廖雪峰老師的Git系列的。

(別看到廖雪峰就以為是廣告了啊,哈哈哈哈,這篇純原創分享)

分享一下三歪的經歷

剛實習的時候,一直都忙着看各種東西。有一天,我學長說:我看你也學了一些基礎了,我們來看看公司的代碼吧,看看我們生產環境是怎麼做的。

於是我學長丟了一個Git鏈接給三歪

https://github.com/ZhongFuCheng3y/3y.git

那三歪做了什麼?三歪去IDEA下把這個Git給Clone下來:

我用Clone完了以後,我學長又補了一句:這個項目不是用master分支的哦,你切換一下分支

三歪:啥?切換分支?咋整?我忘了。

我學長看了下我,貌似不咋會切換分支,就說:“我來吧”。

於是在命令行終端一頓操作后,對三歪說:“好了”

三歪:“我對Git不是很熟悉,之前一直都是在IDEA上操作的。你們一般用命令行多還是圖形界面的多呀?”

我學長:“這沒什麼,反正工具這東西,學學就行,不是什麼大問題。也沒必要說很仔細去學它,就工具嘛”

三歪:“嗯”

時間飛逝,又過了一段時間…

三歪被分配了一個需求,於是就需要新建分支去做這個需求了。所有的標準應用線上走的是master分支,公司通過一個發布系統來控制發布版本、以及整套上下線的流程。

於是我要先在發布系統裡邊新建Git分支:

完了以後,我就在IDEA界面上選擇那個被我新建完的分支

但發現我死活找不到…於是我就問我學長:我在發布系統裡邊新建了分支,為什麼在IDEA上找不到啊?

學長:“怎麼會呢,我看看”。

找了一會,他問我:“你fetch 過了嗎?”

三歪:“啥?”

於是他拿着我的電腦,打開了終端,又以是命令行的方式敲了一頓,問我:“這是不是你新建的分支?“

三歪點了點頭,於是我學長說:”好了,你再看看“。

後來發現,新建完遠程分支,如果在IDEA上要能感知到,可以在pull界面上刷新一下,那就能找到了。

也不是說命令行一定會就比界面牛逼,其實IDEA的Git功能也做得挺好的。現在我都是混合使用,一些操作用命令行,一些操作用IDEA快捷鍵。

commitpush的時候就喜歡用快捷鍵。command+k和command +shift+k我就感覺比敲命令要快不少。

這些都是個人習慣的問題,也無對錯之分,怎麼方便怎麼來。

其實也不是所有的系統都會走發布系統的(有標準應用,非標準應用)。如果要自己寫一個啟動的腳本,一般我們會做些什麼?無非就是用Git拉最新的代碼,然後用maven打個包,然後啟動。

理解Git

如果你看過上一篇《三歪給女朋友講解什麼是Git》應該能大概了解什麼是Git了。

其實我覺得學Git主要理解工作區 -> 暫存區->倉庫 這幾個概念。

我們使用Git其實絕大部分的操作都是在本地上完成的,比如說add 和commit

只有我們push的時候,才會把本地完成好的內容推到遠程倉庫

通過上一篇文章我們知道在每個人的本地都有完整的歷史版本,所以我們可以在本地就能穿梭到不同的版本,然後將修改之後的代碼再重新提交到遠程倉庫上。

所謂的工作區實際上就是我們真正的的本地目錄

我們在本地添加文件后,需要add到暫存區,文件一旦被add到了暫存區,意味着Git能追蹤到這個文件。

當我們修改到一定程度之後,我們會執行一次提交commit,在提交的時候我們會”備註“自己這次的提交修改了什麼內容。

一次commit在Git就是一個版本,Git是版本控制的軟件,我們可以隨意穿梭到任何的版本中,修改代碼。

暫存區是這麼一個概念呢?

暫存區就像購物車,沒到付款的時候你都不確定購物車裡的東西全部都是要的。每拿一件商品就付一次款,那麻煩可大了。

從宏觀上看,Git其實有本地和遠程的概念,只是本地又分了工作區、暫存區、本地倉庫。再次強調:我們操作幾乎都是在本地完成,每個人的本地都會有所有歷史版本信息

我們一般會新建分支去支持每一次的修改。

其實分支這個概念也挺好理解的:我們需要并行開發,同時我們又不關心對方改的是什麼內容,改的是什麼文件。因此我們需要在自己的專屬環境下去修改內容,只要把最終修改完后的內容合併到一個主分支就OK了。

假設三歪做完了,經過校驗通過後,把自己的代碼merge(合併)到origin/master分支后,然後就發布上線啦。

隨後,雞蛋也做完了,自己的分支校驗完了以後,他此時也想把自己的代碼合併到origin/master。不料,他改的代碼跟三歪改的代碼有衝突了(Git不知道選擇誰的的代碼),那雞蛋只能手動merge了。

綜合來看,我們使用Git大多數的場景就是各自分支開發,然後各自在本地commit(提交),最後匯總到master分支。

所以,我們學Git大多數就學怎麼實現分支的增刪改、切換以及版本的穿梭

學習Git的小tips:

Unix/Linux 命令中,- 后一般跟短命令選項(通常是單字母,也有一些命令是例外的),-- 后一般跟長命令選項。如果只有一個單獨的--,後面不緊跟任何選項,則表示命令選項結束,後續的都作為命令的參數而不是選項。

例如:git checkout -- filename filename作為git checkout 的參數,而不是選項。

日常Git使用場景

、如果這個項目的代碼我們在本地還沒有,我們先去GitLab裡邊找對應的Git地址,然後Clone到本地:

git clone https://github.com/ZhongFuCheng3y/3y.git

、接到了新的需求,我們要新建一個分支,然後基於這個分支去開發:

git checkout -b feature/sanwaiAddLog

在開發的時候,我們肯定會有兩個操作:

  • 在原來的基礎上添加新的文件
  • 在原有的文件上修改

、不管怎麼樣,等我們做到一定程度了,我們都會提交代碼。如果我們添加了新的文件,我們需要先add,然後再commit

git add .
git commit  -m "try to commit files to GitHub, i am java3y"

、假設我們一切順利,在沒人打擾的情況下已經寫好了代碼了,然後我們會把自己的分支push到遠程倉庫

git push

、假設我們寫到一半,其他小夥伴已經把他的代碼merge到主分支了,我們也需要把他最新的 代碼給pull拉取下來(可以 git fetch + git merge 替代)。

git pull

如果沒有衝突,那git就會把他的代碼給merge到我當前的分支上。如果有衝突,Git會提醒我去手動解決一下衝突。

、假設我們寫到一半了,現在工作區的代碼都已經commit了。此時同事說要不幫忙一起排查一個問題,同事一般用的是自己分支,於是就得問他:你用的哪個分支啊?於是得把他的分支給拉下來,看看他的代碼哪兒有問題

git fecth -- 手動拉取遠程倉庫更新的信息
git checkout  分支名   -- 切換到他的分支

現在切換到他的分支,相當於你的環境跟他的環境是一模一樣的,於是就可以愉快地一起看Bug了。

、假設我們寫到一半了,現在工作區的代碼還沒commit。現在有同事說要排查問題或者一個新的Bug被發現了,要緊急切換到其他的分支。現在我又不想commit(我就寫了一半,編譯還報着錯誤,沒理由讓我commit吧)。

這時,我會把工作區的代碼先stash到暫存區給保存起來,然後就可以愉快地切換其他的分支了。

git stash

等我解決完另一個bug或者幫別人看完問題了,我再把剛剛保存在暫存區的代碼給撈出來,繼續幹活

git stash pop

、我一直在修Bug,現在的分支已經被我搞得人摸鬼樣了,我非常難受,甚至不知道自己在這個過程中改了多少東西了。

思路已經完全被打亂了,我想回到一個穩定的commit重新出發,重來吧(通過下面的命令,把工作區的代碼都改成對應commit的代碼了)。

git reset --hard  版本號

那我怎麼找到版本號呢?Git也是有日誌的:

git log --pretty=oneline

常用的Git命令

查看Git工作區、暫存區的變更情況(可以知道哪些沒有commit、哪些沒有被Git追蹤):git status

拉取遠程最新的變更到本地:git fetch

切換分支:git checkout 分支名

將代碼還原到某個版本(包括工作目錄):git reset --hard 版本號

查看Git的提交(commit)記錄:git log

將代碼還原到某個版本后,後悔了,想重新回去,但在提交記錄已經找不到了。git reset --hard reset 之後的 commit都給抹殺掉了。找到最近的執行Git命令:git reflog

還原到某個版本了,現在我為了穩健,不想再原來的分支上修改了,再新建一個分支吧(-b 參數把當前分支切換到了要創建的分支上):git checkout -b 分支名

我們把上一次還是”相對穩健“的分支合併到我新建的分支上:git merge 分支

突然想看看現在有多少個分支:git branch -a

新增幾個文件了,隨手git add一下吧

改得差不多了,隨手git commit -m 一下吧,最好還是寫好備註,不然以後等改多了,你都不知道你改了什麼啦。

改完了,提交到遠程吧:git push

想把遠程分支最新的代碼給拉下來,然後合併到本地上。我們可以用git fetchgit merge 來實現,也可以通過git pull來實現。一般我用的都是git fetch+git merge ,這樣會更加可控一些

有的時候,本地分支在master分支,然後忘了切其他的分支去修改,直接在master改了,然後也push到遠程了。等你發現的時候,你會真的想罵自己。

咋辦?最簡單的辦法其實我們還是可以git reset --hard到對應的版本,然後將其修改或者復原,再強制提交到master分支:git push -u origin/master -f

三歪瞎扯

在這篇文章中,我列出的Git常用的命令其實並不多吧。

像很多博客講的difftagconfig之類的命令我都沒有講,我這邊現實開發時這些命令也沒怎麼用過…

如果覺得我說漏的,可以在評論區補充,一起學習。

其實現在IDEA也很強大,很多時候都可以配合IDEA給我們提供的Git去做很多事。有的場景敲命令會比較方便,有的時候就直接圖形化界面就比較方便。

diff 這個功能而言, 肯定還是圖形界面好用一些吧(至少我是這樣認為的

IDEA配合一些快捷鍵,使用Git也能爽得飛起。Git始終也只是一個工具,如果你有興趣可以了解它的實現(我覺得大部分人可能不知道它是怎麼實現的);

如果沒興趣看它的實現,了解它是怎麼使用的,也足夠應付日常的開發場景了。

總的來說,現在的互聯網公司大多數還是用Git的,Git本身使用上其實不難,只要理解了Git是幹嘛的,它有個本地倉庫的概念,它可以來回穿梭各種版本,然後將本地的信息提交到遠程,跟着教程把常用的命令敲敲也差不多了。

如果實在是不懂,也別慌(我都給你們打了個樣了);主動認慫,虛心求教,同事們都不會嫌棄你的。

如果實習之前不知道要準備什麼去公司,要是對Git不了解,我覺得Git可以有佔一席之位。

更多Git命令和參考資料:

  • https://github.com/xjh22222228/git-manual
  • https://juejin.im/post/5edcf3a36fb9a047fa04fbc3
  • https://www.liaoxuefeng.com/wiki/896043488029600

各類知識點總結

下面的文章都有對應的原創精美PDF,在持續更新中,可以來找我催更~

  • 92頁的Mybatis
  • 129頁的多線程
  • 141頁的Servlet
  • 158頁的JSP
  • 76頁的集合
  • 64頁的JDBC
  • 105頁的數據結構和算法
  • 142頁的Spring
  • 58頁的過濾器和監聽器
  • 30頁的HTTP
  • 42頁的SpringMVC
  • Hibernate
  • AJAX
  • Redis
  • ……

涵蓋Java後端所有知識點的開源項目(已有8K+ star):

  • GitHub
  • Gitee訪問更快

我是三歪,一個想要變強的男人,感謝大家的點贊收藏和轉發,下期見。給三歪點個贊,對三歪真的非常重要!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

聚甘新

.Net Core Configuration Etcd數據源

前言

    .Net Core為我們提供了一套強大的Configuration配置系統,使用簡單擴展性強。通過這套配置系統我們可以將Json、Xml、Ini等數據源加載到程序中,也可以自己擴展其他形式的存儲源。今天我們要做的就是通過自定義的方式為其擴展Etcd數據源操作。

何為Etdc

    在使用etcd之前我們先介紹一下Etcd,我相信很多同學都早有耳聞。Etcd是一款高可用、強一致的分佈式KV存儲系統,它內部採用raft協議作為一致性算法,本身也是基於GO語言開發的,最新版本為v3.4.9,具體版本下載地址可參閱官方GitHub地址。相信了解過K8S的同學對這個肯定不陌生,它是K8S的數據管理系統。官方地址為https://etcd.io/。
    在此之前,我相信大家已經了解過很多存儲系統了,Etcd到底能實現了什麼功能呢?其一用於配置中心和服務發現,再者也可以實現分佈式鎖和消息系統。它本身就是基於目錄型存儲,並且內部有一套強大的Watch機制可以監聽針對節點和數據的操作變化,每次對節點的事務操作都會有對於的版本信息。

Etcd VS Zookeeper

通過上面的介紹是不是感覺和Zookeeper有點類似呢,網上有很多很多關於Etcd和Zookeeper的對比文章,大致如下可以得到以下結論

功能 Etcd Zookeeper
分佈式鎖 有(採用節點版本號信息) 有(採用臨時節點和順序臨時節點)
watcher
一致性算法 raft zab
選舉
元數據(metadata)存儲
應用場景 Etcd Zookeeper
發布與訂閱(配置中心) 有(不限次Watch) 有(一次性觸發的,需要重新註冊Watch)
軟負載均衡
命名服務(Naming Service)
服務發現 有(基於租約節點) 有(基於臨時節點)
分佈式通知/協調
集群管理與Master選舉
分佈式鎖
分佈式隊列

說白了就是Zookeeper能幹的活,Etcd也能幹。那既然有了Zookeeper為啥還要選擇Etcd,主要基於以下原因

  • 更輕量級(Etcd基於GO語言開發,Zookeeper基於Java開發)、更易用(開箱即用)
  • 高負載下的穩定讀寫
  • 數據模型的多版本併發控制
  • 穩定的watcher功能,通知訂閱者監聽值的變化(Zookeeper基於數據的監聽是一次性的,每次監聽完成還需重新註冊)
  • 客戶端協議使用GRPC協議,支持語言更廣泛

一言以蔽之,就是不僅實現了Zookeeper的功能,還在很多方面吊打Zookeeper,這麼強大的東西忍不住都要試一試。

在.Net Core中使用Etcd

    在Nuget上可以搜索到很多.Net Core的Etcd客戶端驅動程序,我使用了下載量最多的一個名字叫dotnet-etcd的驅動包,順便找到了它在GayHub上,不好意思手滑打錯了GitHub上的項目地址,大概學習了一下基本的使用方式。其實我們結合Configuration配置這一塊,只需要兩個功能。一個是Get獲取數據,另一個是Watch節點變化(更新數據會用到)。個人認為,前期有目有邊界的學習還是非常重要的。

Configuration擴展Etcd

前面我們講到過自定義擴展Configuration是非常方便的,相信了解過Configuration相關源碼的小夥伴們已經非常熟悉了,大致總結一下分為三步:

  • 編寫IConfigurationBuilder擴展方法,我們這裏叫AddEtcd
  • 編寫實現IConfigurationSource的配置源信息類,我們這裏叫EtcdConfigurationSource
  • 編寫繼承自ConfigurationProvider的ConfigurationSource的配置數據提供類,我們這裏叫EtcdConfigurationProvider

因為微軟已經給我們提供了一部分便利,所以編寫起來還是非常的簡單的。好了,接下來我們開始編寫具體的實現代碼,重點的地方我會在代碼中註釋說明。

首先是定義擴展類EtcdConfigurationExtensions,這個類是針對IConfigurationBuilder的擴展方法,實現如下

public static class EtcdConfigurationExtensions
{
    /// <summary>
    /// AddEtcd擴展方法
    /// </summary>
    /// <param name="serverAddress">Etcd地址</param>
    /// <param name="path">讀取路徑</param>
    /// <returns></returns>
    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress,string path)
    {
        return AddEtcd(builder, serverAddress:serverAddress, path: path,reloadOnChange: false);
    }

    /// <summary>
    /// AddEtcd擴展方法
    /// </summary>
    /// <param name="serverAddress">Etcd地址</param>
    /// <param name="path">讀取路徑</param>
    /// <param name="reloadOnChange">如果數據發送改變是否刷新</param>
    /// <returns></returns>
    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, string serverAddress, string path, bool reloadOnChange)
    {
        return AddEtcd(builder,options => {
            options.Address = serverAddress;
            options.Path = path;
            options.ReloadOnChange = reloadOnChange;
        });
    }

    public static IConfigurationBuilder AddEtcd(this IConfigurationBuilder builder, Action<EtcdOptions> options)
    {
        EtcdOptions etcdOptions = new EtcdOptions();
        options.Invoke(etcdOptions);
        return builder.Add(new EtcdConfigurationSource { EtcdOptions = etcdOptions });
    }
}

這裏我還定義了一個EtcdOptions的POCO,用於承載讀取Etcd的配置屬性

public class EtcdOptions
{
    /// <summary>
    /// Etcd地址
    /// </summary>
    public string Address { get; set; }

    /// <summary>
    /// Etcd訪問用戶名
    /// </summary>
    public string UserName { get; set; }

    /// <summary>
    /// Etcd訪問密碼
    /// </summary>
    public string PassWord { get; set; }

    /// <summary>
    /// Etcd讀取路徑
    /// </summary>
    public string Path { get; set; }

    /// <summary>
    /// 數據變更是否刷新讀取
    /// </summary>
    public bool ReloadOnChange { get; set; }
}

接下來我們定義EtcdConfigurationSource,這個類非常簡單就是返回一個配置提供對象

public class EtcdConfigurationSource : IConfigurationSource
{
    public EtcdOptions EtcdOptions { get; set; }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        return new EtcdConfigurationProvider(EtcdOptions);
    }
}

真正的讀取操作都在EtcdConfigurationProvider里

public class EtcdConfigurationProvider : ConfigurationProvider
{
    private readonly string _path;
    private readonly bool _reloadOnChange;
    private readonly EtcdClient _etcdClient;

    public EtcdConfigurationProvider(EtcdOptions options)
    {
        //實例化EtcdClient
        _etcdClient = new EtcdClient(options.Address,username: options.UserName,password: options.PassWord);
        _path = options.Path;
        _reloadOnChange = options.ReloadOnChange;
    }

    /// <summary>
    /// 重寫加載方法
    /// </summary>
    public override void Load()
    {
        //讀取數據
        LoadData();
        //數據發生變化是否重新加載
        if (_reloadOnChange)
        {
            ReloadData();
        }
    }

    private void LoadData()
    {
        //讀取Etcd里的數據
        string result = _etcdClient.GetValAsync(_path).GetAwaiter().GetResult();
        if (string.IsNullOrEmpty(result))
        {
            return;
        }
        //轉換一下數據結構,這裏我使用的是json格式
        //讀取的數據只要賦值到Data屬性上即可,IConfiguration真正讀取的數據就是存儲到Data的字典數據
        Data = ConvertData(result);
    }

    private IDictionary<string,string> ConvertData(string result)
    {
        byte[] array = Encoding.UTF8.GetBytes(result);
        MemoryStream stream = new MemoryStream(array);
        //JsonConfigurationFileParser是將json數據轉換為Configuration可讀取的結構(複製JsonConfiguration類庫里的)
        return JsonConfigurationFileParser.Parse(stream);
    }

    private void ReloadData()
    {
        WatchRequest request = new WatchRequest()
        {
            CreateRequest = new WatchCreateRequest()
            {
                //需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
                Key = ByteString.CopyFromUtf8(_path)
            }
        };
        //監聽Etcd節點變化,獲取變更數據,更新配置
        _etcdClient.Watch(request, rsp =>
        {
            if (rsp.Events.Any())
            {
                var @event = rsp.Events[0];
                //需要轉換一個格式,因為etcd v3版本的接口都包含在grpc的定義中
                Data = ConvertData(@event.Kv.Value.ToStringUtf8());
                //需要調用ConfigurationProvider的OnReload方法觸發ConfigurationReloadToken通知
                //這樣才能對使用Configuration的類發送數據變更通知
                //比如IOptionsMonitor就是通過ConfigurationReloadToken通知變更數據的
                OnReload();
            }
        });
    }
}

使用方式如下

builder.AddEtcd("http://127.0.0.1:2379", "service/mydemo", true);

順便給大家推薦一個Etcd可視化管理工具ETCD Manager,以便更好的學習Etcd。
到這裏,基本上就結束了,是不是非常簡單。主要還是Configuration本身的設計思路比較清晰,所以實現起來也不費勁。

總結

    以上代碼都已經上傳了我的GitHub,該倉庫還擴展了其他數據源的讀取比如Consul、Properties文件、Yaml文件的讀取,實現思路也都大致相似,有興趣的同學可以自行查閱。由於主要是講解實現思路,可能許多細節並未做處理還望見諒。如果有疑問或者更好的建議,歡迎評論區交流指導。

歡迎掃碼關注 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

聚甘新

Redis 數據結構 之 SDS

SDS(simple dynamic string),簡單動態字符串。s同時它被稱為 Hacking String。hack 的地方就在 sds 保存了字符串的長度以及剩餘空間。sds 的實現在 sds.c 中。

C語言字符串使用長度為n+1的字符數組來表示長度為n的字符串,並且字符數組的最後一個元素總是空字符’\0’,這樣的方式存儲,時存在安全隱患的,並且它不能滿足效率方面的需求。

因此Redis沒有使用C原生的string而是自己構建了SDS。在Redis里,C語言字符串只用於一些無須對字符串值進行修改的地方,比如:日誌。

在Redis中,包含字符串值的鍵值對都是使用SDS實現的,除此之外,SDS還被用於AOF緩衝區、客戶端狀態的輸入緩衝區。

SDS定義

struct sdshdr{
     //字節數組
     char buf[]; 
     //buf數組中已使用字節數量
     int len;
     //buf數組中未使用字節數量
     int free;
}

如上圖所示,len表示該SDS保存了一個6字節長度(不包含結束符)的字符串,free表示該SDS還有6個字節的未使用空間,buf是一個char類型的數組 ,保存了該SDS所存儲的字符串值。

高效

相比C語言字符串,使獲取字符串長度時間複雜度降為O(1)而C原生的獲取長度為O(N) 遍歷整個數組。

安全

同時SDS杜絕緩衝區溢出,不會像C那樣造成數組數據不安全,絕對不會越界。

當需要對SDS進行修改時,API會先檢查SDS當前剩餘空間是否滿足修改之後所需的空間,如果不滿足的話API會自動將SDS的空間擴展至足夠用的空間然後才進行下一步操作,所以SDS不會出現緩衝區溢出問題。

減少內存分配

C語言字原生符串底層是使用一個n+1個字符長度的char類型數據實現的,所以每次增長或縮短一個原生字符串,程序都要對這個字符串數組進行一次內存重分配操作:

同時因為內存重分配涉及複雜的算法,並且可能需要執行系統調用,所以它通常是一個比較耗時的操作。Redis經常被用於速度要求嚴苛、數據被頻繁修改的場合,如果每次修改字符串都需要執行一次內存重分配的話,那麼對於性能會造成很大影響。

SDS 在分配了內存之後(往往空間會存在盈餘,也就是空間的預分配),然後自己通過len 和 free 來維護已使用的和未使用的內存,不再依賴系統來重新劃分,這樣能有效的提升性能。

空間預分配

用於字符串增長操作,當字符串增長時,程序會先檢查需不需要對SDS空間進行擴展,如果需要擴展,程序不僅會為SDS分配修改所必要的空間,還會為SDS分配額外的未使用空間,額外分配的未使用空間公式如下:

SDS空間 < 1MB

如果對SDS修改之後,SDS的長度(修改之後len屬性的值)小於1MB,那麼則分配和len屬性同樣大小的未使用空間,這時SDS的len屬性和free屬性的值相同。如:如果修改之後SDS的len將變為10字節,那麼程序也會分配10字節的未使用空間,SDS的buf數組實際長度變為10 + 10 + 1 = 21(額外一個字節用於保存結束符\n)

SDS空間 > 1MB

如果對SDS修改之後,SDS的長度大於等於1MB,那麼程序會分配1MB的未使用空間。如:修改之後的len將變為10MB,那麼程序會分配1MB的未使用空間,SDS的bug數組長度為10MB + 1MB + 1byte

SDS空間 > 512MB

Game over~ 報錯!

惰性空間釋放

用於優化SDS的字符串收縮操作,當字符串收縮時,程序不會立即執行內存重分配來回收收縮后內存多出來的空間,而是使用free屬性記錄下來,以備將來使用。

通過空間預分配,Redis可以減少連續執行字符串增長操作所需的內存重分配次數,通過惰性空間釋放,SDS避免了縮短字符串時所需的內存重分配操作,併為將來由可能的增長操作提供了優化。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

聚甘新

「大家都累了」 美中仍保守 曼谷氣候談判陷泥沼

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

聚甘新

加州簽了! 2045年100%乾淨能源目標入法

環境資訊中心外電;姜唯 翻譯;林大利 審校;稿源:ENS

加州州長布朗10日簽署參議院100號法案(SB 100),將「100%乾淨電力」正式設立為法定目標。

繼提早四年達成「2020年減排13%、經濟成長26%」目標後,「SB 100」將使加州的再生能源比例標準更加積極,2025年必須達到50%電力由再生能源供應,2030年要達到60%,2045年實現零碳電網。

加州州長布朗簽署參議院100號法案(SB 100)。圖片來源:Office of the Governor

州長訂定碳中和目標  減碳不涉核電

為了確保全球暖化對策不只侷限於電業(佔加州溫室氣體排放量的16%),布朗還發布了一項行政命令,指示加州要在2045年實現碳中和,之後則要實現淨負排碳。

目前全球有20多個國家和40多個地方政府宣布,最晚要在本世紀中實現碳中和。

為了實現目標,加州將持續減少碳污染,同時增加森林、土壤和其他自然地景的碳儲存和空氣品質及公共衛生改善計畫,尤其是在該州受影響最嚴重的社區。

加州也將陸續實施一系列因應暖化的長期行動。上週,布朗簽署了另一項法案,禁止加州沿海進行新的聯邦海上石油鑽探活動,並宣布加州反對聯邦政府擴大加州公共土地上石油鑽探的計畫。1968年至今,加州都沒有開放沿海地區的新石油和天然氣租賃。

雖然加州政府定義的乾淨能源有三種,州政府在其網站上的指出,加州正在逐步淘汰核電,現階段也並不考慮新建核電廠。

減碳聯盟「Under2 Coalition」 規模跨六大洲、佔全球經濟四成

原本加州計畫於2020年達成減排13%、同時經濟成長26%,結果此目標提早四年達成。從2015到2016年,加州減排量大約等於減少240萬輛汽車上路,省下15億加侖的汽柴油燃料。

此外,布朗幫助建立全美和全球的減碳合作聯盟「Under2 Coalition」。該聯盟起源於加州與德國巴登-符騰堡州之間的合作關係,現在已納入橫跨六大洲的206個各級政府,共代表13億人口和30兆美元的GDP,相當於全球人口的17%和全球經濟的40%。

聯盟成員做出了一些重要承諾,包括減少相當於1990年水準80%至95%的溫室氣體排放,以及2050年加州每人每年碳排少於2公噸。

California Passes 100 Percent Clean Electricity Bill SACRAMENTO, California, September 10, 2018 (ENS)

Putting his stamp of approval on California’s global climate leadership, Governor Jerry Brown today signed Senate Bill 100, which sets a 100 percent clean electricity goal for the state. The governor also issued an executive order establishing a new target to achieve carbon neutrality – both by 2045.

With Governor Brown’s executive order, California establishes the most ambitious carbon neutrality commitment of the more than 20 countries and at least 40 cities, states and provinces planning to go carbon neutral by mid-century or sooner.

SB 100 advances the state’s existing Renewables Portfolio Standard, which establishes how much of the electricity system should be powered from renewable energy resources, to 50 percent by 2025 and 60 percent by 2030.

It also puts California on the bold path to implement a zero-carbon electricity grid by 2045.

To ensure California is combating global warming beyond the electric sector, which represents 16 percent of the state’s greenhouse gas emissions, the governor’s executive order directs the state to achieve carbon neutrality by 2045 and net negative greenhouse gas emissions after that.

The state will reach its goals with continued reductions of carbon pollution and increased carbon sequestration in forests, soils and other natural landscapes and programs focused on improving air quality and public health, especially in California’s most impacted communities.

These actions are the latest in a long series of actions by California to deal with the warming climate. Late last week, Governor Brown also signed legislation to block new federal offshore oil drilling along California’s coast and announced the state’s opposition to the federal government’s plan to expand oil drilling on public lands in California. The entirety of the state’s coast has been off-limits to new oil and gas leases for more than 30 years, and the state has not issued a lease for offshore oil or gas production since 1968.

The state has met its 2020 target four years early, reducing emissions 13 percent while growing the economy 26 percent.

From 2015 to 2016, emissions reductions were roughly equal to taking 2.4 million cars off the road, saving 1.5 billion gallons of gasoline and diesel fuel.

In addition, Governor Brown has helped establish and expand coalitions of partners across the nation and globe committed to curbing carbon pollution.

The Under2 Coalition, which originated from a partnership between California and the German state of Baden-Württemberg, now includes 206 jurisdictions on six continents that collectively represent 1.3 billion people and $30 trillion in GDP – equivalent to 17 percent of the global population and 40 percent of the global economy.

Members of the Under2 Coalition have made a number of key commitments, including reducing greenhouse gas emissions equivalent to 80 to 95 percent below 1990 levels or to less than two annual metric tons for each person in California by 2050.

※ 全文及圖片詳見:

作者

如果有一件事是重要的,如果能為孩子實現一個願望,那就是人類與大自然和諧共存。

於特有生物研究保育中心服務,小鳥和棲地是主要的研究對象。是龜毛的讀者,認為龜毛是探索世界的美德。

延伸閱讀

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※教你寫出一流的銷售文案?

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※回頭車貨運收費標準

※別再煩惱如何寫文案,掌握八大原則!

※超省錢租車方案

※產品缺大量曝光嗎?你需要的是一流包裝設計!

聚甘新

創新減廢 啤酒公司淘汰塑膠套環 改用可回收膠

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※超省錢租車方案

※別再煩惱如何寫文案,掌握八大原則!

※回頭車貨運收費標準

※教你寫出一流的銷售文案?

FB行銷專家,教你從零開始的技巧

聚甘新

2017第二屆中國中原國際充電站(樁)技術展

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※回頭車貨運收費標準

聚甘新