Java并發編程學習(二)

線程的狀態

有說5種的,有說6種的
5種的,從操作系統層面來講
在這里插入圖片描述

  • 初始狀態:也就是語言層面創建了線程對象,還未與操作系統線程關聯。Java中也就是new了一個線程,還未調用。
  • 可運行狀態:(就緒狀態)也就是該線程已經被創建,也就是java中調用了start()方法,已經與操作系統關聯了,已經可以被CPU調度了。
  • 運行狀態:指線程被CPU調度了,獲取了CPU的時間片,已經在執行代碼中了(注意:當CPU的時間片用完,也就是CPU自己的調度,切換線程上下文,該線程就會從運行狀態重新到可運行狀態,等待下一次被CPU調度,獲取時間片)
  • 阻塞狀態:比如sleep了,wait了啥的,就會到阻塞狀態,此時CPU就不會分時間片給這些線程。而是會選擇分給那些可運行狀態的線程。等sleep完了,再回到可運行狀態
  • 終止狀態:代碼運行完畢生命周期結束
    6種狀態的說法,根據Java Api層面描述
    根據Thread.State枚舉,有六種狀態,new、runnable、blocked、waiting、time_waiting、terminated
    在這里插入圖片描述
    源碼:
public enum State {/*** Thread state for a thread which has not yet started.* 尚未啟動的線程的線程狀態。*/NEW,/*** Thread state for a runnable thread.  A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.* 可運行線程的線程狀態。處于可運行狀態的線程正在Java虛擬機中執行,* 但它可能正在等待來自操作系統(如處理器)的其他資源。*/RUNNABLE,/*** Thread state for a thread blocked waiting for a monitor lock.* A thread in the blocked state is waiting for a monitor lock* to enter a synchronized block/method or* reenter a synchronized block/method after calling* {@link Object#wait() Object.wait}.* 等待監視器鎖的線程的線程狀態。處于阻塞狀態的線程正在等待監視器鎖* 進入同步blockmethod或在調用后重新進入同步blockmethod*/BLOCKED,/*** Thread state for a waiting thread.* A thread is in the waiting state due to calling one of the* following methods:* 等待線程的線程狀態。線程由于調用以下方法之一而處于等待狀態:* <ul>*   <li>{@link Object#wait() Object.wait} with no timeout</li>*   <li>{@link #join() Thread.join} with no timeout</li>*   <li>{@link LockSupport#park() LockSupport.park}</li>* </ul>** <p>A thread in the waiting state is waiting for another thread to* perform a particular action.* 處于等待狀態的線程正在等待另一個線程執行特定的操作** For example, a thread that has called <tt>Object.wait()</tt>* on an object is waiting for another thread to call* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on* that object. A thread that has called <tt>Thread.join()</tt>* is waiting for a specified thread to terminate.* 例如,一個線程在一個對象上調用了<tt> object. wait()<tt>,* 正在等待另一個線程在該對象上調用<tt> object. notify()<tt>或<tt> object. notifyall ()<tt>。* 調用了<tt> thread .join()<tt>的線程正在等待指定的線程終止。*/WAITING,/*** Thread state for a waiting thread with a specified waiting time.* A thread is in the timed waiting state due to calling one of* the following methods with a specified positive waiting time:* 指定等待時間的等待線程的線程狀態。線程處于定時等待狀態,因為調用了以下方法之一,并指定了正等待時間:* <ul>*   <li>{@link #sleep Thread.sleep}</li>*   <li>{@link Object#wait(long) Object.wait} with timeout</li>*   <li>{@link #join(long) Thread.join} with timeout</li>*   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>*   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>* </ul>*/TIMED_WAITING,/*** Thread state for a terminated thread.* The thread has completed execution.* 終止線程的線程狀態。線程已完成執行。*/TERMINATED;}

在這里插入圖片描述

  • NEW 線程剛被創建,但是還沒有調用 start() 方法
  • RUNNABLE 當調用了 start() 方法之后,注意,Java API 層面的 RUNNABLE 狀態涵蓋了 操作系統 層面的
    【可運行狀態】、【運行狀態】和【阻塞狀態】(由于 BIO[也就是io讀取文件的阻塞,java也是認為在運行。而不像sleep這樣的阻塞] 導致的線程阻塞,在 Java 里無法區分,仍然認為
    是可運行)
  • BLOCKED , WAITING , TIMED_WAITING 都是 Java API 層面對【阻塞狀態】的細分,后面會在狀態轉換一節
    詳述
  • TERMINATED 當線程代碼運行結束
    運行狀態、可運行狀態、阻塞狀態,在java中都屬于runnable狀態,因為不管你怎么樣,反正就是可以被CPU調度的狀態

六種狀態的例子

public static void main( String[] args ) throws InterruptedException {Thread t1 = new Thread() {@Overridepublic void run() {log.debug("running...");}};t1.setName("t1");Thread t2 = new Thread() {@Overridepublic void run() {while (true) {//runnable:分到時間片,未分到時間片,io阻塞}}};t2.setName("t2");t2.start();Thread t3 = new Thread() {@Overridepublic void run() {log.debug("running...");}};t3.setName("t3");t3.start();Thread t4 = new Thread() {@Overridepublic void run() {synchronized (JUCStudy.class) {try {Thread.sleep(1000000);} catch (InterruptedException e) {e.printStackTrace();}}}};t4.setName("t4");t4.start();Thread t5 = new Thread() {@Overridepublic void run() {try {t2.join();//要等待t2,但是t2死循環,或者是不知道時間,所以就是waiting,沒有時間的等待} catch (InterruptedException e) {e.printStackTrace();}}};t5.setName("t5");t5.start();Thread t6 = new Thread() {@Overridepublic void run() {synchronized (JUCStudy.class) {//因為t4在用鎖,t6就拿不到,就會到blocked狀態try {Thread.sleep(1000000);} catch (InterruptedException e) {e.printStackTrace();}}}};t6.setName("t6");t6.start();log.debug("t1 state {}",t1.getState());//NEW (新建線程對象,只是new了,還沒start,也無法被CPU分配時間片)log.debug("t2 state {}",t2.getState());//RUNNABLE (可運行狀態,能被CPU分配時間片就是可運行狀態)log.debug("t3 state {}",t3.getState());//TERMINATED (線程正常執行結束)log.debug("t4 state {}",t4.getState());//TIMED_WAITING (睡眠等有時間的等待)log.debug("t5 state {}",t5.getState());//WAITING (使用了join方法等,需要等待其他線程結束,不知道時間的等待)log.debug("t6 state {}",t6.getState());//BLOCKED (需要對象鎖,而對象鎖被其他線程用了,還未釋放鎖,陷入阻塞)}

共享模型

正常來講,單線程訪問共享資源是沒有問題的,因為他們不會交替訪問。但是多線程交替訪問共享資源,就有可能出現類似"臟讀"的情況,比如線程一要計算用共享資源從1累加到100,結果還沒算出來就沒有時間片了,而線程二來讀取這個共享資源,就會出現數據錯誤。
一段代碼塊內如果存在對共享資源的多線程讀寫操作,稱這段代碼塊為臨界區

static int counter = 0;
static void increment()
// 臨界區
{counter++;
}
static void decrement()
// 臨界區
{counter--;
}

ok,上面是臨界區對共享資源的一種競爭,要怎么解決這樣的問題呢?

synchronized 解決方案

應用之互斥

為了避免臨界區的競態條件發生,有多種手段可以達到目的

  • 阻塞式的解決方案: synchronized、Lock
  • 非阻塞式的解決方法:原子變量

本次課使用阻塞式的解決方案:synchronized,來解決上述問題,即俗稱的【對象鎖】,它采用互斥的方式讓同一
時刻至多只有一個線程能持有【對象鎖】,其它線程再想獲取這個【對象鎖】時就會阻塞住。這樣就能保證擁有鎖
的線程可以安全的執行臨界區內的代碼,不用擔心線程上下文切換

注意
雖然 java 中互斥和同步都可以采用 synchronized 關鍵字來完成,但它們還是有區別的:

  • 互斥是保證臨界區的競態條件發生,同一時刻只能有一個線程執行臨界區代碼
  • 同步是由于線程執行的先后、順序不同、需要一個線程等待其它線程運行到某個點

synchonized語法

synchronized (對象){//臨界區:也就是要對共享資源讀取的代碼區域
}

拿了所鎖之后,不論有沒有時間片,都不會釋放鎖,只有整個臨界區運行我完畢了才釋放鎖。釋放之后會喚醒其他所有阻塞、等待鎖釋放的線程,至于哪個線程來爭得到這把鎖,就由CPU來決定了
在這里插入圖片描述

例子

static int counter = 0;
static final Object room = new Object();
public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 5000; i++) {synchronized (room) {counter++;}}}, "t1");Thread t2 = new Thread(() -> {for (int i = 0; i < 5000; i++) {synchronized (room) {counter--;}}}, "t2");t1.start();t2.start();t1.join();t2.join();log.debug("{}",counter);
}
  • 如果把 synchronized(obj) 放在 for 循環的外面,如何理解?-- 原子性(原來是鎖住了++和–的代碼,也就是要么加一次要么減一次,而放在外面就變成了,一次性先加完,再一次性減完)
  • 如果 t1 synchronized(obj1) 而 t2 synchronized(obj2) 會怎樣運作?–鎖對象 (肯定要同一把鎖啊,不同鎖,我等你干什么)
  • 如果 t1 synchronized(obj) 而 t2 沒有加會怎么樣?如何理解?-- 鎖對象 (不用鎖我就執行咯,你有所沒鎖關我啥事,鎖要多個地方用,只給一個臨界區上鎖沒啥意義)

鎖的面向對象的改進
說白了就是把鎖弄在對象里面
里面的方法加鎖,鎖就是對象自己

/*** Hello world!*/
@Slf4j
public class JUCStudy {public static void main(String[] args) throws InterruptedException {Room room = new Room();Thread t1 = new Thread(() -> {for (int j = 0; j < 5000; j++) {room.increment();}}, "t1");Thread t2 = new Thread(() -> {for (int j = 0; j < 5000; j++) {room.decrement();}}, "t2");t1.start();t2.start();t1.join();t2.join();log.debug("count: {}", room.get());}
}
class Room {int value = 0;public void increment() {synchronized (this) {value++;}}public void decrement() {synchronized (this) {value--;}}public int get() {synchronized (this) {return value;}}
}

進一步優化,synchroized其他語法

class Test{public synchronized void test() {}
}
等價于
class Test{public void test() {synchronized(this) {}}
}
class Test{public synchronized static void test() {}
}
等價于
class Test{public static void test() {synchronized(Test.class) {}}
}

不加synchronized是無法保證方法的原子性的

網上所謂的"線程八鎖"

其實沒啥意思,就8個例子,都很簡單

@Slf4j(topic = "c.Number")
class Number{public synchronized void a() {log.debug("1");}public synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n1.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public synchronized void a() {sleep(1);log.debug("1");}public synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n1.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public synchronized void a() {sleep(1);log.debug("1");}public synchronized void b() {log.debug("2");}public void c() {log.debug("3");}
}
public static void main(String[] args) {Number n1 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n1.b(); }).start();new Thread(()->{ n1.c(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public synchronized void a() {sleep(1);log.debug("1");}public synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();Number n2 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n2.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public static synchronized void a() {sleep(1);log.debug("1");}public synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n1.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public static synchronized void a() {sleep(1);log.debug("1");}public static synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n1.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public static synchronized void a() {sleep(1);log.debug("1");}public synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();Number n2 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n2.b(); }).start();
}
@Slf4j(topic = "c.Number")
class Number{public static synchronized void a() {sleep(1);log.debug("1");}public static synchronized void b() {log.debug("2");}
}
public static void main(String[] args) {Number n1 = new Number();Number n2 = new Number();new Thread(()->{ n1.a(); }).start();new Thread(()->{ n2.b(); }).start();
}

變量的線程安全分析

成員變量和靜態變量是否線程安全?

  • 如果它們沒有共享,則線程安全
  • 如果它們被共享了,根據它們的狀態是否能夠改變,又分兩種情況
    • 如果只有讀操作,則線程安全
    • 如果有讀寫操作,則這段代碼是臨界區,需要考慮線程安全

局部變量是否線程安全?

  • 局部變量是線程安全的
  • 但局部變量引用的對象則未必
    • 如果該對象沒有逃離方法的作用訪問,它是線程安全的
    • 如果該對象逃離方法的作用范圍,需要考慮線程安全

先看一個成員變量的例子

@Slf4j
public class JUCStudy {static final int THREAD_NUMBER = 2;static final int LOOP_NUMBER = 200;public static void main(String[] args) {ThreadUnsafe test = new ThreadUnsafe();for (int i = 0; i < THREAD_NUMBER; i++) {new Thread(() -> {test.method1(LOOP_NUMBER);}, "Thread" + i).start();}}
}class ThreadUnsafe {ArrayList<String> list = new ArrayList<>();public void method1(int loopNumber) {for (int i = 0; i < loopNumber; i++) {// { 臨界區, 會產生競態條件method2();method3();// } 臨界區}}private void method2() {list.add("1");}private void method3() {list.remove(0);}
}

說白了就是兩個線程,一起去操作同一個對象里的成員變量,這不很明顯,這個成員變量就相當于是共享變量了,一起對其進行讀寫操作,肯定會出現線程安全問題,這里是一個線程執行方法還沒加完,另一個線程就來執行減的操作,就會出現IndexOutOfBoundsException,下標越界異常。
很明顯,就是因為無論是method2還是method3都是對同一個變量進行操作,而且還是同一個對象。

Exception in thread "Thread1" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.remove(ArrayList.java:496) at cn.itcast.n6.ThreadUnsafe.method3(TestThreadSafe.java:35) at cn.itcast.n6.ThreadUnsafe.method1(TestThreadSafe.java:26) at cn.itcast.n6.TestThreadSafe.lambda$main$0(TestThreadSafe.java:14) at java.lang.Thread.run(Thread.java:748)

常見的線程安全類

  • String
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent 包下的類

這里說它們是線程安全的是指,多個線程調用它們同一個實例的某個方法時,是線程安全的。也可以理解為:
(說白了就是上述說的安全類,new一個對象后里面的方法都是加鎖的,所以就線程安全了嘛,見下面put()方法源碼:)

public static void main(String[] args) {Hashtable table = new Hashtable();new Thread(()->{table.put("key", "value1");}).start();new Thread(()->{table.put("key", "value2");}).start();
}

put()方法源碼

public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;int hash = key.hashCode();int index = (hash & 0x7FFFFFFF) % tab.length;@SuppressWarnings("unchecked")Entry<K,V> entry = (Entry<K,V>)tab[index];for(; entry != null ; entry = entry.next) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;}
  • 它們的每個方法是原子的
  • 但注意它們多個方法的組合不是原子的,見后面分析

重點來了!!!->但注意它們多個方法的組合不是原子的
線程安全類方法的組合
分析下面代碼是否線程安全?(不安全)

Hashtable table = new Hashtable();
// 線程1,線程2
if( table.get("key") == null) {table.put("key", value);
}

這不很明顯不安全嘛,很好理解,兩個方法里面的代碼都是線程安全的,這是因為給兩個方法都上了鎖,但是兩個方法外面那一層并沒有加鎖,所以這兩個方法一起用,多個線程來執行的話,哪個線程先執行哪個方法的順序就成了問題。所以要想他們的組合也是保持原子性,那肯定就得在外層也加個鎖嘍
在這里插入圖片描述
在這里插入圖片描述

不可變類線程安全性

String、Integer 等都是不可變類,因為其內部的狀態不可以改變,因此它們的方法都是線程安全的
或許有疑問,String 有 replace,substring 等方法【可以】改變值啊,那么這些方法又是如何保證線程安全的呢?說白了,其實這些類的方法,里面都是創建了新的String、Integer對象,所以內部其實就是不可變的,變了其實就是new了新對象,所以是說他們的內容方法都是線程安全的。


例子
背景:servlet實例是運行在tomcat里面,所以多個現場是共用這一個servlet的

public class MyServlet extends HttpServlet {// 是否安全?不安全,安全的是HashTableMap<String,Object> map = new HashMap<>();// 是否安全?安全String S1 = "...";// 是否安全?安全---不可變即安全final String S2 = "...";// 是否安全?不安全Date D1 = new Date();// 是否安全?不安全,只是說這個對象不變,但是里面的屬性還是可能改變的。就跟前面有提到過的,一個對象的外部安全,但是里面的屬性能變。final Date D2 = new Date();public void doGet(HttpServletRequest request, HttpServletResponse response) {// 使用上述變量}
}

Monitor概念

Java對象頭

簡單了解一下,里面有mark word和klass word等,一般是這兩個,里面有字節,指向對應的地址,就知道java類對應到底是什么類。

Monitor(synchorized底層原理的鎖)

Monitor翻譯:監視器、管程
底層原理全是概念,好復雜,頂多用來應對面試,不想記。

輕量級鎖

輕量級鎖的應用場景:如果一個對象有多線程訪問,但多線程訪問的時間是錯開的(也就是沒有競爭),那么可以使用輕量級鎖來優化

輕量級鎖對使用者是透明的,即語法仍是synchronized

假設有兩個方法同步塊,利用同一個對象加鎖

    static final Object obj = new Object();public static void method1(){synchronized (obj){//同步塊Amethod2();}}public static void method2() {synchronized (obj){//同步塊B}
}

聽不懂…

鎖膨脹(指的是一個過程,由輕量級鎖變成重量級鎖)

如果在嘗試加輕量級鎖的過程中,CAS操作無法成功,這是一種情況就是有其他線程為此對象加上了輕量級鎖(有競爭),這是需要進行鎖膨脹,將輕量級鎖變為重量級鎖。也就是最簡單意義上的鎖。

static Object obj = new Object();
public static void method1() {synchronized (obj) {//同步塊}
}

聽不懂…

自旋優化

重量級鎖競爭的時候,還可以使用自旋來進行優化,如果當前線程自旋成功(即這時候持鎖線程已經退出了同步塊,釋放了鎖),這時,當前線程就可以避免阻塞
聽不懂…

偏向鎖

看不懂…
上面說看不懂的,難的都是理論知識,頂多應付面試。實際項目開發用不上。需要的可以自己去搜相關知識。

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

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

相關文章

Docker方式安裝人人影視離線完整安裝包

本文軟件由網友 ルリデ 推薦&#xff1b; 上周&#xff0c;人人影視創始人宣布將人人影視二十年字幕數據開源分享 目前提供了兩種使用方式&#xff1a; “在線應用” &#xff1a;意味著需要有互聯網才可以使用。官方提供了網站&#xff1a;https://yyets.click “離線使用” …

Leetcode 3389. Minimum Operations to Make Character Frequencies Equal

Leetcode 3389. Minimum Operations to Make Character Frequencies Equal 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3389. Minimum Operations to Make Character Frequencies Equal 1. 解題思路 這一題從答題從test的結果來說來說做出的人很少&#xff0c;主要確實有些…

大文件處理的終極武器:Yield詳解

【大文件處理的終極武器&#xff1a;Yield詳解】&#x1f680; 一、大文件處理的痛點 內存限制數據量巨大傳統方法效率低 二、Yield解決方案 def read_large_file(file_path):with open(file_path, r) as file:# 每次只讀取一行&#xff0c;而不是全文for line in file:yie…

SpringBoot 學習

SpringBoot 學習 什么是 Springboot Spring Boot 是 Spring 提供的一個子項目&#xff0c;用于快速構建 Spring 應用程序 傳統的問題&#xff1a; 導入依賴繁瑣項目配置繁瑣 SpringBoot 的特性 起步依賴&#xff1a;整合所有 web 的依賴配置好了自動配置&#xff1a;bean…

到達率的變化動態調整服務器的服務率,實現負載均衡,提高資源利用效率

中心可以根據任務到達率的變化動態調整服務器的服務率,實現負載均衡,提高資源利用效率 服務率和到達率 中心可以根據任務到達率的變化動態調整服務器的服務率,實現負載均衡,提高資源利用效率服務率(Service Rate)到達率(Arrival Rate)控制參數實現負載均衡的方法在云計…

最新全開源IM即時通訊系統源碼(PC+WEB+IOS+Android)部署指南

全開源IM&#xff08;即時通訊&#xff09;系統源碼部署是一個復雜但系統的過程&#xff0c;涉及多個組件和步驟。以下是一個詳細的部署指南&#xff0c;旨在幫助開發者或系統管理員成功部署一個全開源的IM系統&#xff0c;如OpenIM。      IM即時通訊系統源碼準備工作   …

CAD c# 生成略縮圖預覽

代碼如下&#xff1a; using (Transaction tr currentdb.TransactionManager.StartTransaction()){//當前數據庫開啟事務using (Database tempdb new Database(false, true)) //創建臨時數據庫(兩個參數&#xff1a;是否創建符號表&#xff0c;不與當前文檔關聯){try{Bitmap …

CloudberryDB(二) 演化路線圖

CloudberryDB 制定了演化路線圖&#xff08;https://github.com/orgs/cloudberrydb/discussions/369&#xff09;并在逐步改進&#xff0c;這是 Cloudberry Database 發揮獨特價值之處。 計劃、正在進行或已完成的一些工作。 支持輕松升級 PostgreSQL 內核版本。 原有 Greenp…

單片機:實現呼吸燈(附帶源碼)

單片機實現呼吸燈詳細解讀 呼吸燈是一種常見的燈光效果&#xff0c;廣泛應用于電子產品、汽車、家居照明等領域。其基本特性是通過逐漸增亮和減弱的方式&#xff0c;使得燈光呈現出“呼吸”的效果&#xff0c;給人一種平緩、舒適的視覺感受。在嵌入式系統中&#xff0c;呼吸燈…

[面試題]--索引用了什么數據結構?有什么特點?

答&#xff1a;使用了B樹&#xff1a; 時間復雜度&#xff1a;O(logN),可以有效控制樹高 B樹特點&#xff1a; 1.葉子節點之間有相互鏈接的作用&#xff0c;會指向下一個相近的兄弟節點。 MySQL在組織葉子節點使用的是雙向鏈表 2.非葉子節點的值都保存在葉子節點當中 MySQL非葉…

ansible自動化運維(五)roles角色管理

Roles角色管理 角色&#xff08;roles&#xff09;是ansible自1.2版本開始引入的新特性&#xff0c;用于層次性&#xff0c;結構化地組織playbook。 roles能夠根據層次型結構自動裝載變量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。簡單的…

操作系統:文件系統

目錄 1、文件 概念&#xff1a; UNIX文件分類&#xff1a; 2、文件系統 3、文件的訪問方式 順序訪問 隨機訪問 4、文件的組織 邏輯組織 物理組織 5、倒排結構&#xff08;了解&#xff09; 5、文件目錄 文件控制塊&#xff08;FCB&#xff09; ?編輯 目錄項 單…

單元測試-FATAL ERROR in native method: processing of -javaagent failed

文章目錄 前言單元測試-FATAL ERROR in native method: processing of -javaagent failed1. 報錯信息2. 解決方案 前言 如果您覺得有用的話&#xff0c;記得給博主點個贊&#xff0c;評論&#xff0c;收藏一鍵三連啊&#xff0c;寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運…

決策曲線分析(DCA)中平均凈收益用于評價模型算法(R自定義函數)

決策曲線分析&#xff08;DCA&#xff09;中平均凈收益用于評價模型算法 DCA分析雖然不強調用來評價模型算法或者變量組合的優劣&#xff0c;但是實際應用過程中感覺DCA曲線的走勢和模型的效能具有良好的一致性&#xff0c;其實這種一致性也可以找到內在的聯系&#xff0c;比如…

快速且靠譜的簡單安裝 PostgreSQL 15 yum 安裝postgis3.3

快速且靠譜的簡單安裝 PostgreSQL 15 yum 安裝postgis3.3 1、確保已經安裝了PostgreSQL數據庫。2、添加PostGIS的EPEL倉庫3、使用YUM安裝PostGIS4、以下為其他安裝方式&#xff0c;一個個去找源碼的編譯安裝&#xff0c;過程較為繁瑣&#xff08;不熟路的不推薦&#xff09; 要…

工業大數據分析算法實戰-day05

文章目錄 day05分而治之中的MARS算法神經網絡逼近能力解釋 day05 今天是第5天&#xff0c;昨日從統計分析開始利用統計學的知識判斷當前樣本的分布以及估計總體的參數和假設檢驗的情況&#xff0c;以及介紹了線性回歸算法的相關優化點&#xff0c;但是畢竟線性回歸是線性劃分的…

在Ubuntu服務器上備份文件到自己的百度網盤

文章目錄 概述安裝bypy同步文件定時任務腳本 概述 之前自購了一臺阿里云服務器&#xff0c;系統鏡像為Ubuntu 22.04&#xff0c; 并且搭建了LNMP開發環境&#xff08;可以參考&#xff1a;《Ubuntu搭建PHP開發環境操作步驟(保姆級教程)》&#xff09;。由于項目運行中會產生附…

safe area helper插件

概述 顯示不同機型的必能顯示的區域 實現步驟 引入safearea&#xff0c;引入其中的safearea的csharp 為cancas加入gameobject gameobject中加入safearea腳本 將UI作為這個gameobject的子物體&#xff0c;就可以完成顯示

Unity 獲取鼠標點擊位置物體貼圖顏色

實現 Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit)) {textureCoord hit.textureCoord;textureCoord.x * textureMat.width;textureCoord.y * textureMat.height;textureColor textureMat.GetPixel(Mathf.Flo…

基于深度學習的貓狗識別系統【深度學習課設】

&#x1f3c6; 作者簡介&#xff1a;席萬里 ? 個人網站&#xff1a;https://dahua.bloggo.chat/ ?? 一名后端開發小趴菜&#xff0c;同時略懂Vue與React前端技術&#xff0c;也了解一點微信小程序開發。 &#x1f37b; 對計算機充滿興趣&#xff0c;愿意并且希望學習更多的技…