synchronized 異常_由淺入深,Java 并發編程中的 Synchronized

synchronized 作用

synchronized 關鍵字是 Java 并發編程中線程同步的常用手段之一。

1.1 作用:

  • 確保線程互斥的訪問同步代,鎖自動釋放,多個線程操作同個代碼塊或函數必須排隊獲得鎖,
  • 保證共享變量的修改能夠及時可見,獲得鎖的線程操作完畢后會將所數據刷新到共享內存區;
  • 不解決重排序,但保證有序性。

1.2 用法:

  • 修飾實例方法synchronized 關鍵詞作用在方法的前面,用來鎖定方法,其實默認鎖定的是 this 對象。
public class Thread1 implements Runnable{    //共享資源(臨界資源)    static int i=0;    //如果沒有synchronized關鍵字,輸出小于20000    public synchronized void increase(){        i++;    }    public void run() {        for(int j=0;j<10000;j++){            increase();        }    }    public static void main(String[] args) throws InterruptedException {        Thread1 t=new Thread1();        Thread t1=new Thread(t);        Thread t2=new Thread(t);        t1.start();        t2.start();        t1.join();//主線程等待t1執行完畢        t2.join();//主線程等待t2執行完畢        System.out.println(i);    }}
44a33bc30e412c52c3dd8a052fd148df.png
  • 修飾靜態方法synchronized 還是修飾在方法上,不過修飾的是靜態方法,等價于鎖定的是 Class 對象。
 public class Thread1 {    //共享資源(臨界資源)    static int i = 0;    //如果沒有synchronized關鍵字,輸出小于20000    public static synchronized void increase() {        i++;    }    public static void main(String[] args) throws InterruptedException {        Thread t1 = new Thread(new Runnable() {            public void run() {                for (int j = 0; j < 10000; j++) {                    increase();                }            }        });        Thread t2 = new Thread(new Runnable() {            @Override            public void run() {                for (int j = 0; j < 10000; j++) {                    increase();                }            }        });        t1.start();        t2.start();        t1.join();//主線程等待t1執行完畢        t2.join();//主線程等待t2執行完畢        System.out.println(i);    }}
bf81ffb4e5a9688bd47759b4a824ab54.png
  • 修飾代碼塊用法是在函數體內部對于要修改的參數區間用 synchronized 來修飾,相比與鎖定函數這個范圍更小,可以指定鎖定什么對象。
public class Thread1 implements Runnable {    //共享資源(臨界資源)    static int i = 0;    @Override    public void run() {        for (int j = 0; j < 10000; j++) {            //獲得了String的類鎖            synchronized (String.class) {                i++;            }        }    }    public static void main(String[] args) throws InterruptedException {        Thread1 t = new Thread1();        Thread t1 = new Thread(t);        Thread t2 = new Thread(t);        t1.start();        t2.start();        t1.join();        t2.join();        System.out.println(i);    }}
a1a3ea7d6aa4590a051be92a13c4d717.png

總結:

  1. synchronized 修飾的實例方法,多線程并發訪問時,只能有一個線程進入,獲得對象內置鎖,其他線程阻塞等待,但在此期間線程仍然可以訪問其他方法。
synchronized 修飾的靜態方法,多線程并發訪問時,只能有一個線程進入,獲得類鎖,其他線程阻塞等待,但在此期間線程仍然可以訪問其他方法。synchronized 修飾的代碼塊,多線程并發訪問時,只能有一個線程進入,根據括號中的對象或者是類,獲得相應的對象內置鎖或者是類鎖每個類都有一個類鎖,類的每個對象也有一個內置鎖,它們是互不干擾的,也就是說一個線程可以同時獲得類鎖和該類實例化對象的內置鎖,當線程訪問非 synchronzied 修飾的方法時,并不需要獲得鎖,因此不會產生阻塞。

管程

管程(英語:Monitors,也稱為監視器) 在操作系統中是很重要的概念,管程其實指的是管理共享變量以及管理共享變量的操作過程。有點扮演中介的意思,管程管理一堆對象,多個線程同一時候只能有一個線程來訪問這些東西。

管程可以看做一個軟件模塊,它是將共享的變量和對于這些共享變量的操作封裝起來,形成一個具有一定接口的功能模塊,進程可以調用管程來實現進程級別的并發控制。

進程只能互斥地使用管程,即當一個進程使用管程時,另一個進程必須等待。當一個進程使用完管程后,它必須釋放管程并喚醒等待管程的某一個進程。

管程解決互斥問題相對簡單,需要把共享變量以及共享變量的操作都封裝在一個類中。

18028de76ef548f408c6b478cd9700d4.png

當線程 A 和線程 B 需要獲取共享變量 count 時,就需要調用 get 和 set 方法,而 get 和 set 方法則保證互斥性,保證每次只能有一個線程訪問。

生活中舉例管程,比如鏈家店長分配給每個中介管理一部分二手房源,多個客戶通過中介進行房屋買賣。

  • 中介就是管程。
  • 多個二手房源被一個中介管理中,就是一個管程管理著多個系統資源。
  • 多個客戶就相當于多個線程。

Synchronzied 的底層原理

對象頭解析

我們知道在 Java 的 JVM 內存區域中一個對象在堆區創建,創建后的對象由對象頭、實例變量、填充數據三部分組成。這三部分功能如下:

  1. 填充數據:由于虛擬機要求對象起始地址必須是 8 字節的整數倍。填充數據不是必須存在的,僅僅是為了字節對齊。
實例變量:存放類的屬性數據信息,包括父類的屬性信息,這部分內存按 4 字節對齊。對象頭:主要包括兩部分 Klass Point 跟 Mark Word。
a7a6264dc51edba838e1511f9ec02b16.png

Klass Point (類型指針):是對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

Mark Word (標記字段):這一部分用于儲存對象自身的運行時的數據,如哈希碼、GC 分代年齡、鎖狀態標志、鎖指針等。這部分數據在 32 bit 和 64 bit 的虛擬機中大小分別為 32 bit 和 64 bit,考慮到虛擬機的空間效率,Mark Word 被設計成一個非固定的數據結構,以便在極小的空間中存儲盡量多的信息,它會根據對象的狀態復用自己的存儲空間(跟 ConcurrentHashMap 里的標志位類似),詳細情況如下圖:

bb1dab3fab083362ed6ebba307a20938.png

synchronized 不論是修飾方法還是代碼塊,都是通過持有修飾對象的鎖來實現同步,synchronized 鎖對象是存在對象頭 Mark Word。

其中,輕量級鎖和偏向鎖是 Java6 對 synchronized 鎖進行優化后新增加的。這里我們主要分析一下重量級鎖,也就是通常說 synchronized 的對象鎖。所標識位為 10,其中指針指向的是 monitor 對象(也稱為管程或監視器鎖)的起始地址。每個對象都存在著一個 monitor 與之關聯。

d0bc0345183b6b56403e8ba6736c3fae.png

反匯編查看

分析對象的 monitor 前我們先通過反匯編看下同步方法跟同步方法塊在匯編語言級別是什么樣的指令。

public class SynchronizedTest {    public synchronized void doSth(){        System.out.println("Hello World");    }    public void doSth1(){        synchronized (SynchronizedTest.class){            System.out.println("Hello World");        }    }}

javac SynchronizedTest .java 然后 javap -c SynchronizedTest 反編譯后看匯編指令如下:

 public synchronized void doSth();    descriptor: ()V    flags: ACC_PUBLIC, ACC_SYNCHRONIZED //  這是重點 方法鎖    Code:      stack=2, locals=1, args_size=1         0: getstatic     #2                           3: ldc           #3             5: invokevirtual #4                           8: return  public void doSth1();    descriptor: ()V    flags: ACC_PUBLIC    Code:      stack=2, locals=3, args_size=1         0: ldc           #5                          2: dup         3: astore_1         4: monitorenter  //   進入同步方法         5: getstatic     #2                           8: ldc           #3                          10: invokevirtual #4                        13: aload_1        14: monitorexit  //正常時 退出同步方法        15: goto          23        18: astore_2        19: aload_1        20: monitorexit  // 異常時 退出同步方法        21: aload_2        22: athrow        23: return

我們可以看到 Java 編譯器為我們生成的字節碼。在對于 doSth 和 doSth1 的處理上稍有不同。也就是說,JVM 對于同步方法和同步代碼塊的處理方式不同。對于同步方法,JVM 采用ACC_SYNCHRONIZED 標記符來實現同步。對于同步代碼塊。JVM 采用 monitorenter、monitorexit 兩個指令來實現同步。

ACC_SYNCHRONIZED

方法級的同步是隱式的。

同步方法的常量池中會有一個 ACC_SYNCHRONIZED 標志。當某個線程要訪問某個方法的時候,會檢查是否有 ACC_SYNCHRONIZED,如果有設置,則需要先獲得監視器鎖,然后開始執行方法,方法執行之后再釋放監視器鎖。

這時如果其他線程來請求執行方法,會因為無法獲得監視器鎖而被阻斷住。值得注意的是,如果在方法執行過程中發生了異常,并且方法內部并沒有處理該異常,那么在異常被拋到方法外面之前監視器鎖會被自動釋放。

monitorenter 跟 monitorexit

可以把執行 monitorenter 指令理解為加鎖,執行 monitorexit 理解為釋放鎖。

每個對象維護著一個記錄著被鎖次數的計數器。未被鎖定的對象的該計數器為 0,當一個線程獲得鎖(執行 monitorenter )后,該計數器自增變為 1 ,當同一個線程再次獲得該對象的鎖的時候,計數器再次自增。當同一個線程釋放鎖(執行 monitorexit 指令)的時候,計數器再自檢。

當計數器為 0 的時候。鎖將被釋放,其他線程便可以獲得鎖。

結論:

同步方法和同步代碼塊底層都是通過 monitor 來實現同步的。兩者區別:同步方式是通過方法中的 access_flags 中設置 ACC_SYNCHRONIZED 標志來實現,同步代碼塊是通過 monitorenter 和 monitorexit 來實現。

monitor 解析

每個對象都與一個 monitor 相關聯,而 monitor 可以被線程擁有或釋放,在Java 虛擬機( HotSpot )中,monitor 是由 ObjectMonitor 實現的,其主要數據結構如下(位于 HotSpot 虛擬機源碼 ObjectMonitor.hpp 文件,C++實現的)。

ObjectMonitor() {    _count        = 0;      //記錄數    _recursions   = 0;      //鎖的重入次數    _owner        = NULL;   //指向持有ObjectMonitor對象的線程     _WaitSet      = NULL;   //調用wait后,線程會被加入到_WaitSet    _EntryList    = NULL ;  //等待獲取鎖的線程,會被加入到該列表}

monitor 運行圖如下:

ce8e12f6dda772f4a74ab45f39423c63.png

對于一個 synchronized 修飾的方法(代碼塊)來說:

  • 當多個線程同時訪問該方法,那么這些線程會先被放進_EntryList 隊列,此時線程處于 blocked 狀態;
  • 當一個線程獲取到了對象的 monitor 后,那么就可以進入 running 狀態,執行方法塊,此時,ObjectMonitor 對象的_owner 指向當前線程,_count 加 1 表示當前對象鎖被一個線程獲取;
  • 當 running 狀態的線程調用 wait() 方法,那么當前線程釋放 monitor 對象,進入 waiting 狀態,ObjectMonitor 對象的_owner 變為 null,_count 見 1,同時線程進入_WaitSet 隊列,直到有線程調用 notify() 方法喚醒該線程,則該線程進入_EntryList 隊列,競爭到鎖再進入_owner區;
  • 如果當前線程執行完畢,那么也釋放 monitor 對象,ObjectMonitor 對象的_owner 變為 null,_count 見 1。

因為監視器鎖(monitor)是依賴于底層的操作系統的 Mutex Lock 來實現的,而操作系統實現線程之間的切換時需要從用戶態轉換到核心態(具體可看CXUAN 寫的 OS 哦),這個狀態之間的轉換需要相對比較長的時間,時間成本相對較高,這也是早期的 synchronized 效率低的原因。慶幸在 Java 6 之后Java 官方對從 JVM 層面對 synchronized 較大優化最終提升顯著,Java 6 之后,為了減少獲得鎖和釋放鎖所帶來的性能消耗,引入了鎖升級的概念。

鎖升級

synchronized 鎖有四種狀態:無鎖、偏向鎖、輕量級鎖、重量級鎖。

這幾個狀態會隨著競爭狀態逐漸升級,鎖可以升級但不能降級,但是偏向鎖狀態可以被重置為無鎖狀態。科學性的說這些鎖之前我們先看個簡單通俗的例子來加深印象。

通俗說法理解各種鎖

偏向鎖、輕量級鎖和重量級鎖之間的關系,首先打個比方:假設現在廁所只有一個位置,每個使用者都有打開門鎖的鑰匙。必須打開門鎖才能使用廁所。其中小明、小紅理解為兩個線程,上廁所理解為執行同步代碼,門鎖理解為同步代碼的鎖

  • 小明今天吃壞了東西需要反復去廁所,如果小明每次都要開鎖就很耽誤時間,于是門鎖將小明的臉記錄下來(假設那個鎖是智能鎖),下次小明再來的時候門鎖會自動識別出是小明來了,然后自動開鎖,這樣就省去了小明拿鑰匙開門的過程,此時門鎖就是偏向鎖,也可以理解為偏向小明的鎖。
接下來,小紅又去上廁所,試圖將廁所的門鎖設置為偏向自己的偏向鎖,于是發現門鎖無法偏向自己,因為此時門鎖已是偏向小明的偏向鎖。于是小紅很生氣,要求門鎖撤銷對小明的偏向,當然,小明也不同意門鎖偏向小紅。于是等小明用完廁所之后,門鎖撤銷了對任何人的偏向(只要出現競爭的情況,就會撤銷偏向鎖)。這個過程就是撤銷偏向鎖。此時門鎖升級為輕量級鎖。等小明出來以后,輕量級鎖正式生效 。下一次小明和小紅同時來廁所,誰跑的快誰先走到門前,開門后將門鎖拿進廁所,并將門鎖打開以后拿進廁所里,將門反鎖,于是在門外原來放門鎖的位置放置了一個有人的標志(這個標識可以理解為指向門鎖的指針,或者理解為作為鎖的 Java 對象頭的 Mark Word 值),這時,小紅看到有人以后很著急,催著里面的人出來時馬上進去,于是不斷的來敲門,問小明什么時候出來。這個過程就是自旋。反復敲了幾次以后,小明受不了了,對小紅喊話,說你別敲了,等我用完廁所我告訴你,于是小紅去一邊等著(線性阻塞)。此時門鎖升級為重量級鎖。升級為重量級鎖的后果就是,小紅不再反復敲門,小明在上完廁所以后必須告訴小紅一聲,否則小紅就會一直等著。

結論:

偏向鎖在只有一個人上廁所時非常高效,省去了開門的過程。

輕量級鎖在有多人上廁所但是每個人使用的特別快的時候,比較高效,因為會出現這種現象,小紅敲門的時候正好趕上小明出來,這樣就省得小明出來告訴小紅以后小紅才能進去,但是這樣可能會出現小紅敲門失敗的情況(就是敲門時小明還沒用完)。

重量級鎖相比與輕量級鎖的多了一步小明呼喚小紅的步驟,但是卻省掉了小紅反復去敲門的過程,但是能保證小紅去廁所時廁所一定是沒人的。

偏向鎖

經過 HotSpot 作者大量的研究發現:大多數時候是不存在鎖競爭的,經常是一個線程多次獲得同一個鎖,因此如果每次都要競爭鎖會增大很多沒有必要付出的代價,為了降低獲取鎖的代價,才引入的偏向鎖。核心思想:

如果一個線程獲得了鎖,那么鎖就進入偏向模式,此時 Mark Word 的結構也變為偏向鎖結構,當這個線程再次請求鎖時,無需再做任何同步操作,即獲取鎖的過程。

這樣就省去了大量有關鎖申請的操作,從而也就提供程序的性能。所以,對于沒有鎖競爭的場合,偏向鎖有很好的優化效果,畢竟極有可能連續多次是同一個線程申請相同的鎖。但是對于鎖競爭比較激烈的場合,偏向鎖就失效了,因為這樣場合極有可能每次申請鎖的線程都是不相同的。

因此這種場合下不應該使用偏向鎖,否則會得不償失,需要注意的是,偏向鎖失敗后,并不會立即膨脹為重量級鎖,而是先升級為輕量級鎖。

具體流程:當線程 1 訪問代碼塊并獲取鎖對象時,會在 java 對象頭和棧幀中記錄偏向的鎖的 threadID,因為偏向鎖不會主動釋放鎖。因此以后線程 1 再次獲取鎖的時候,需要比較當前線程的 threadID 和 Java 對象頭中的threadID 是否一致,如果一致(還是線程 1 獲取鎖對象),則無需使用 CAS 來加鎖、解鎖;如果不一致(其他線程,如線程 2 要競爭鎖對象,而偏向鎖不會主動釋放因此還是存儲的線程 1 的 threadID),那么需要查看Java 對象頭中記錄的線程 1 是否存活,如果沒有存活,那么鎖對象被重置為無鎖狀態,其它線程(線程 2)可以競爭將其設置為偏向鎖;如果存活,那么立刻查找該線程(線程 1)的棧幀信息,如果還是需要繼續持有這個鎖對象,那么暫停當前線程 1,撤銷偏向鎖,升級為 輕量級鎖,如果線程 1 不再使用該鎖對象,那么將鎖對象狀態設為無鎖狀態,重新偏向新的線程。

輕量級鎖

輕量級鎖考慮的是競爭鎖對象的線程不多,而且線程持有鎖的時間也不長的情景。因為阻塞線程需要高昂的耗時實現 CPU 從用戶態轉到內核態的切換,如果剛剛阻塞不久這個鎖就被釋放了,那這個代價就有點得不償失了,因此這個時候就干脆不阻塞這個線程,讓它自旋這等待鎖釋放。

原理跟升級:線程 1 獲取輕量級鎖時會先把鎖對象的對象頭 MarkWord 復制一份到線程 1 的棧幀中創建的用于存儲鎖記錄的空間(稱為DisplacedMarkWord ),然后使用 CAS 把對象頭中的內容替換為線程 1 存儲的鎖記錄(DisplacedMarkWord)的地址;

如果在線程 1 復制對象頭的同時(在線程 1 CAS 之前),線程 2 也準備獲取鎖,復制了對象頭到線程 2 的鎖記錄空間中,但是在線程 2 CAS 的時候,發現線程 1 已經把對象頭換了,「線程 2 的 CAS 失敗,那么線程 2 就嘗試使用自旋鎖來等待線程 1 釋放鎖」。自旋鎖簡單來說就是讓線程 2 在循環中不斷 CAS 嘗試獲得鎖對象。

但是如果自旋的時間太長也不行,因為自旋是要消耗 CPU 的,因此自旋的次數是有限制的。比如 10 次或者 100 次,如果自旋次數到了線程 1 還沒有釋放鎖,或者線程 1 還在執行,線程 2 還在自旋等待,那么這個時候輕量級鎖就會膨脹為重量級鎖。重量級鎖把除了擁有鎖的線程都阻塞,防止 CPU 空轉。

31f1021496b056d12a2ff8e50c32f7a0.png

鎖消除

消除鎖是虛擬機另外一種鎖的優化,這種優化更徹底,Java 虛擬機在 JIT 編譯時通過對運行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過這種方式消,除沒有必要的鎖,可以節省毫無意義的請求鎖時間,我們知道StringBuffer 是線程安全的,里面包含鎖的存在,但是如果我們在函數內部使用 StringBuffer 那么代碼會在 JIT 后會自動將鎖釋放掉哦。

對比如下:

鎖狀態優點缺點適用場景偏向鎖加鎖解鎖無需額外消耗,跟非同步方法時間相差納秒級別如果競爭線程多,會帶來額外的鎖撤銷的消耗基本沒有其他線程競爭的同步場景輕量級鎖競爭的線程不會阻塞而是在自旋,可提高程序響應速度如果一直無法獲得會自旋消耗CPU少量線程競爭,持有鎖時間不長,追求響應速度重量級鎖線程競爭不會導致 CPU 自旋跟消耗 CPU 資源線程阻塞,響應時間長很多線程競爭鎖,切鎖持有時間長,追求吞吐量時候

PS:ReentrantLock 底層實現依賴于特殊的 CPU 指令,比如發送 lock 指令和 unlock 指令,不需要用戶態和內核態的切換,所以效率高。而synchronized 底層由監視器鎖(monitor)是依賴于底層的操作系統的Mutex Lock 需要用戶態和內核態的切換,所以效率會低一些。

鎖升級流程圖

最后奉上 unbelievableme 繪制的鎖升級大圖。

036c689c087eeba5a24af776cc194f39.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396521.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396521.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396521.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

mysql正則通配符全解_mysql正則表達式與通配符

擴展正則表達式的一些字符是&#xff1a; “.”匹配任何單個的字符。 一個字符類“[...]”匹配在方括號內的任何字符。例如&#xff0c;“[abc]”匹配“a”、“b”或“c”。為了命名字符的一個范圍&#xff0c;使用一個“-”。“[a-z]”匹配任何小寫字母&#xff0c;而“[0-9…

dos常用文件操作命令

1、DIR 含義&#xff1a; 顯示指定目錄下的文件和子目錄列表 類型&#xff1a; 內部命令 格式&#xff1a; DIR[drive:][path][filename][/p][/w][/A[[:]attributes]][/O[[:]sortorder]][/S][/B][/L] 舉例&#xff1a; DIR DIR D:\px2 DIR D:\px2\*.txt DIR /A:D /O:D 2、COPY…

使您的Java代碼聞起來很新鮮

by Marco Massenzio由Marco Massenzio 使您的Java代碼聞起來很新鮮 (Make your Java code smell nice and fresh) A few years ago I joined a startup working on a cloud enterprise service that was originally built by an offshore team.幾年前&#xff0c;我加入了一家…

MySQL時間戳與日期格式的相互轉換

MySQL時間戳與日期格式的相互轉換&#xff0c;PHP時間戳與日期格式的相互轉換 MySQL: 獲取當前時間SELECT NOW(); // 2018/10/11 14:22:51 時間日期格式轉換成時間戳格式&#xff0c;UNIX_TIMESTAMP()SELECT UNIX_TIMESTAMP(NOW()); // 1539238930 時間戳格式轉換成時間日期格式…

Linux內存分配機制之伙伴系統和SLAB

轉載請注明原文地址&#xff1a;http://www.cnblogs.com/ygj0930/p/6539590.html 內核內存管理的一項重要工作就是如何在頻繁申請釋放內存的情況下&#xff0c;避免碎片的產生。這就要求內核采取靈活而恰當的內存分配策略。通常&#xff0c;內存分配一般有兩種情況&#xff1a…

this.$modal.confirm 自定義按鈕關閉_自定義函數,讓你玩轉Excel得心應手

讓“自動更正”輸入統一的文本&#xff0c;你是不是經常為輸入某些固定的文本,如《電腦報》而煩惱呢?那就往下看吧。1.執行“工具→自動更正”命令,打開“自動更正”對話框。2.在“替換”下面的方框中輸入“pcw”(也可以是其他字符,“pcw”用小寫),在“替換為”下面的方框中輸…

php mysql 排名算法_MySQL PHP:優化排名查詢和計數子查詢

這是原始數據,并希望根據得分(count(tbl_1.id))對它們進行排名.[tbl_1]id | name1 | peter2 | jane1 | peter2 | jane3 | harry3 | harry3 | harry3 | harry4 | ron因此,制作臨時表(tbl_2)來計算每個id的分數.SELECT id, name, COUNT( id ) AS scoreFROM tbl_1GROUP BY idORDER…

CCF-CSP 最大的矩形

問題描述在橫軸上放了n個相鄰的矩形&#xff0c;每個矩形的寬度是1&#xff0c;而第i&#xff08;1 ≤ i ≤ n&#xff09;個矩形的高度是hi。這n個矩形構成了一個直方圖。例如&#xff0c;下圖中六個矩形的高度就分別是3, 1, 6, 5, 2, 3。請找出能放在給定直方圖里面積最大的矩…

Stack Overflow 2016年對50,000名開發人員進行的調查得出的見解

Today, Stack Overflow released the results of their 2016 survey of more than 50,000 developers.今天&#xff0c;Stack Overflow發布了他們2016年對50,000多名開發人員進行的調查的結果。 I’ve combed through this big document to bring you the most surprising ins…

web管理

1.站點根目錄下查找是否被放置webshell***根據語句判斷是不是PHP***腳本# find /storage/www/ -name "*.php" | xargs grep-in --color "eval("# grep -i --include*.php -r system\s*\( /storage/www/2.統計訪問日志中來自同ip出現的次數分析盜鏈、***、機…

MySQL的主從復制云棲社區_MySQL-主從復制

前言前篇說了作為運維在數據庫塊最起碼要會兩大技能&#xff0c;今天來說說第二技能--主從復制隨著業務的增長&#xff0c;一臺數據庫服務器以滿足不了需求了&#xff0c;負載過重&#xff0c;這時候就需要減壓&#xff0c;實現負載均衡讀寫分離&#xff0c;一主一從或一主多從…

數據存儲(SharedPreferences存儲)

SharedPreferences是通過 鍵值對 的方式存儲數據SharedPreferences是通過鍵值對的方式存儲的 將數據存儲到SharedPreferences中有3種方法&#xff1a;1.Context類中的getSharedPreferences()方法2.Activity類中的getPreferences()方法3.PreferencesManager類中的getDefaultShar…

編程程序的名稱要記住嗎_學習編程時要記住的5件事

編程程序的名稱要記住嗎by Kurt由庫爾特 學習編程時要記住的5件事 (5 Things to Remember When You’re Learning to Program) Learning to program is challenging. Aside from choosing a language or setting up a development environment that you know nothing about, t…

mysql 數據分析的步驟_數據分析8個主要步驟

# 在對數據進行分析時&#xff0c;主要細分為明確目標、應用思維和如下8個具體步驟&#xff1a;1、讀取數據2、清洗數據3、操作數據4、轉換數據5、整理數據6、分析數據7、展現數據8、總結報告接下來將介紹使用python來具體處理數據&#xff0c;包括上面幾個步驟的實現&#xff…

python學習的一個定位_python學習之——selenium元素定位

web自動化測試按步驟拆分&#xff0c;可以分為四步操作&#xff1a;定位元素&#xff0c;操作元素&#xff0c;獲取返回結果&#xff0c;斷言(返回結果與期望結果是否一致)&#xff0c;最后自動出測試報告。其中定位元素尤為關鍵&#xff0c;此篇是使用webdriver通過頁面各個元…

Invoker

Invoker 是實體&#xff0c;dubbo外其他對象的轉化。轉載于:https://www.cnblogs.com/gtaxmjld/p/9786894.html

如何在開源社區貢獻代碼_如何在15分鐘內從瀏覽器獲得您的第一個開源貢獻

如何在開源社區貢獻代碼Matt Mullenweg, founder of Automattic, recently offered this advice to aspiring developers: “Contribute to open source.”Automattic的創始人Matt Mullenweg最近向有抱負的開發人員提供了以下建議 &#xff1a;“ 致力于開源。 ” Mullenweg —…

小心情。

從一開始學習html到現在的nodejs&#xff0c;也有段時間了&#xff0c;那個時候什么都不知道&#xff0c;記得一兩年之前還沉迷在一些網絡技術的圈子里面&#xff0c;每天看著那些大牛&#xff0c;感覺都很是厲害&#xff0c;每一項技術總是那樣的讓我著迷&#xff0c;從易語言…

一、win7下安裝yii2

作者&#xff1a;PHP學習網 出處&#xff1a;http://www.viphper.com/?p1159 本文版權歸作者&#xff0c;歡迎轉載&#xff0c;但未經作者同意必須保留此段聲明&#xff0c;且在文章頁面明顯位置給出原文連接&#xff0c;否則保留追究法律責任的權利。 之前在liunx上安裝過yii…

js獲取瀏覽器滾動條距離頂端的距離

js獲取瀏覽器滾動條距離頂端的距離 一、jQuery獲取的相關方法 jquery 獲取滾動條高度獲取瀏覽器顯示區域的高度 &#xff1a;$(window).height(); 獲取瀏覽器顯示區域的寬度 &#xff1a;$(window).width(); 獲取頁面的文檔高度 &#xff1a;$(document).height(); 獲取頁面的文…