聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖

2022年11月03日11:45:03 科技 1172

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

寫在前邊

  • 走到哪都有各種瑣事,在MySQL中咱已經聊透了各種瑣事 ->MySQL鎖機制&&事務,今天來看看Java裡邊的鎖升級過程,以及各種鎖之間的比較,悲觀樂觀,粗化消除~

四種鎖的Markword

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

優先程度

  • 偏向鎖->輕量級鎖-(先自旋不行再膨脹)>重量級鎖(不會自旋直接阻塞)

輕量級鎖

只是棧中一個鎖對象,不是monitor這種重量級

輕量級鎖的使用場景是:如果一個對象雖然有多個線程要對它進行加鎖,但是加鎖的時間是錯開的(也就是沒有人可以競爭的,所以不會出現阻塞的情況),那麼可以使用輕量級鎖來進行優化。輕量級鎖對使用者是透明的,即語法仍然是synchronized,假設有兩個方法同步塊,利用同一個對象加鎖

static final Object obj = new Object();
public static void method1() {
synchronized( obj ) {
// 同步塊 A
method2();
}
}
public static void method2() {
synchronized( obj ) {
// 同步塊 B
}
}
複製代碼
  1. 每次指向到synchronized代碼塊時,都會創建鎖記錄(Lock Record)對象,每個線程都會包括一個鎖記錄的結構,鎖記錄內部可以儲存對象的Mark Word(用來改變對象的lock record編碼)和對象引用reference (表示指向哪個對象)

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 讓鎖記錄中的Object reference指向對象,並且嘗試用CAS(compare and sweep)替換Object對象的Mark Word(表示加鎖) , 將對象的Mark Word更新為指向Lock Record的指針,並將Mark Word 的值存入鎖記錄中 (等同於將Lock Record里的owner指針指向對象的Mark Word。)

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 如果cas替換成功,那麼對象的對象頭儲存的就是鎖記錄的地址和狀態01,如下所示

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 如果cas失敗,有兩種情況 如果是其它線程已經持有了該Object的輕量級鎖,那麼表示有競爭,將進入鎖膨脹階段 如果是自己的線程已經執行了synchronized進行加鎖,那麼那麼再添加一條 Lock Record 作為重入的計數

且此時新的一條Lock Record中,對象的MarkWord為null(相當於被前一個搶了)

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 當線程退出synchronized代碼塊的時候,如果獲取的是取值為 null 的鎖記錄,表示有重入,這時重置鎖記錄,表示重入計數減一

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 當線程退出synchronized代碼塊的時候,如果獲取的鎖記錄取值不為 null,那麼**使用cas將Mark Word的值恢復給對象 ** 成功則解鎖成功 失敗,則說明輕量級鎖進行了鎖膨脹或已經升級為重量級鎖,進入重量級鎖解鎖流程

總結

  • 加鎖和解鎖都是用CAS來交換Lock Record

鎖膨脹

如果在嘗試加輕量級鎖的過程中,cas操作無法成功,這是有一種情況就是其它線程已經為這個對象加上了輕量級鎖,這是就要進行鎖膨脹,將輕量級鎖變成重量級鎖。

  1. 當 Thread-1 進行輕量級加鎖時,Thread-0 已經對該對象加了輕量級鎖

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 這時 Thread-1 加輕量級鎖失敗,進入鎖膨脹流程 即為對象申請Monitor鎖,讓Object指向重量級鎖地址,然後自己進入Monitor 的EntryList 變成BLOCKED阻塞狀態

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. Thread-0 推出synchronized同步塊時,使用cas將Mark Word的值恢復給對象頭,失敗,那麼會進入重量級鎖的解鎖過程,即按照Monitor的地址找到Monitor對象,將Owner設置為null,喚醒EntryList 中的Thread-1線程

總流程

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

自旋優化

為了讓當前線程「稍等一下」,我們需讓當前線程進行自旋,如果在自旋完成後前面鎖定同步資源的線程已經釋放了鎖,那麼當前線程就可以不必阻塞而是直接獲取同步資源,從而避免切換線程的開銷。這就是自旋鎖

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

重量級鎖競爭的時候,還可以使用自旋來進行優化,如果當前線程自旋成功(即在自旋的時候持鎖的線程釋放了鎖),那麼當前線程就可以不用進行上下文切換就獲得了鎖

  1. 自旋重試成功的情況

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

  1. 自旋重試失敗的情況,自旋了一定次數還是沒有等到持鎖的線程釋放鎖

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

自旋會佔用 cpu 時間,單核 CPU 自旋就是浪費,多核 CPU 自旋才能發揮優勢。在 Java 6 之後自旋鎖是自適應的,比如對象剛剛的一次自旋操作成功過,那麼認為這次自旋成功的可能性會高,就多自旋幾次;反之,就少自旋甚至不自旋,總之,比較智能。Java 7 之後不能控制是否開啟自旋功能

自適應自旋鎖

自旋鎖在JDK1.4.2中引入,使用-XX:+UseSpinning來開啟。JDK 6中變為默認開啟,並且引入了自適應的自旋鎖(適應性自旋鎖)。

自適應意味着自旋的時間(次數)不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態來決定。如果在同一個鎖對象上,自旋等待剛剛成功獲得過鎖,並且持有鎖的線程正在運行中,那麼虛擬機就會認為這次自旋也是很有可能再次成功,進而它將允許自旋等待持續相對更長的時間。如果對於某個鎖,自旋很少成功獲得過,那在以後嘗試獲取這個鎖時將可能省略掉自旋過程,直接阻塞線程,避免浪費處理器資源。

在自旋鎖中 另有三種常見的鎖形式: TicketLock、CLHlock和MCSlock

偏向鎖

在輕量級的鎖中,我們可以發現,如果同一個線程對同一2對象進行重入鎖時,也需要執行CAS操作,這是有點耗時的,所以java6開始引入了偏向鎖,只有第一次使用CAS時將對象的Mark Word頭設置為入鎖線程ID,之後這個入鎖線程再進行重入鎖時,發現線程ID是自己的,那麼就不用再進行CAS來加鎖和解鎖了

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

偏向狀態

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

一個對象的創建過程

  1. 如果開啟了偏向鎖(默認是開啟的),那麼對象剛創建之後,Mark Word 最後三位的值101,並且這是它的Thread,epoch,age都是0,在加鎖的時候進行設置這些的值.
  2. 偏向鎖默認是延遲的,不會在程序啟動的時候立刻生效,如果想避免延遲,可以添加虛擬機參數來禁用延遲:-XX:BiasedLockingStartupDelay=0來禁用延遲
  3. 注意:處於偏向鎖的對象解鎖後,線程 id 仍存儲於對象頭中

加上虛擬機參數-XX:BiasedLockingStartupDelay=0進行測試

public static void main(String[] args) throws InterruptedException {
Test1 t = new Test1();
    //加鎖前
test.parseObjectHeader(getObjectHeader(t));
    //加鎖後
synchronized (t){
test.parseObjectHeader(getObjectHeader(t));
}
    //釋放鎖後
test.parseObjectHeader(getObjectHeader(t));
} 

//輸出結果如下,三次輸出的狀態碼都為101
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
    
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
    
biasedLockFlag (1bit): 1
LockFlag (2bit): 01 
複製代碼

禁用偏向鎖

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

測試禁用:如果沒有開啟偏向鎖,那麼對象創建後最後三位的值為001,這時候它的hashcode,age都為0,hashcode是第一次用到hashcode時才賦值的。在上面測試代碼運行時在添加 VM 參數-XX:-UseBiasedLocking禁用偏向鎖(禁用偏向鎖則優先使用輕量級鎖),退出synchronized狀態變回001

  1. 測試代碼:虛擬機參數-XX:-UseBiasedLocking
  2. 輸出結果如下,最開始狀態為001,然後加輕量級鎖變成00,最後恢復成001
biasedLockFlag (1bit): 0
LockFlag (2bit): 01
LockFlag (2bit): 00
biasedLockFlag (1bit): 0
LockFlag (2bit): 01 
複製代碼

撤銷偏向鎖-hashcode方法

測試 hashCode:當調用對象的hashcode方法的時候就會撤銷這個對象的偏向鎖,因為使用偏向鎖時沒有位置存**hashcode**的值了 而輕量級鎖存在lockRecord,重量級鎖存在monitor

  1. 測試代碼如下,使用虛擬機參數-XX:BiasedLockingStartupDelay=0 ,確保我們的程序最開始使用了偏向鎖!但是結果顯示程序還是使用了輕量級鎖。
public static void main(String[] args) throws InterruptedException {
Test1 t = new Test1();
    //撤銷偏向鎖
t.hashCode();
test.parseObjectHeader(getObjectHeader(t));
synchronized (t){
test.parseObjectHeader(getObjectHeader(t));
}
test.parseObjectHeader(getObjectHeader(t));
} 

輸出結果
biasedLockFlag (1bit): 0
LockFlag (2bit): 01
    
LockFlag (2bit): 00
biasedLockFlag (1bit): 0
    
LockFlag (2bit): 01 
複製代碼

撤銷偏向鎖-其它線程使用對象

這裡我們演示的是偏向鎖撤銷變成輕量級鎖的過程,那麼就得滿足輕量級鎖的使用條件,就是沒有線程對同一個對象進行鎖競爭,我們使用wait 和 notify 來輔助實現

  1. 代碼,虛擬機參數-XX:BiasedLockingStartupDelay=0確保我們的程序最開始使用了偏向鎖!
  2. 輸出結果,最開始使用的是偏向鎖,但是第二個線程嘗試獲取對象鎖時,發現本來對象偏向的是線程一,那麼偏向鎖就會失效,加的就是輕量級鎖
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
biasedLockFlag (1bit): 1
LockFlag (2bit): 01
LockFlag (2bit): 00
biasedLockFlag (1bit): 0
LockFlag (2bit): 01 
複製代碼

撤銷偏向鎖 - 調用 wait/notify

會使對象的鎖變成重量級鎖,因為wait/notify方法只有重量級鎖才支持

批量重偏向

如果對象被多個線程訪問,但是沒有競爭,這時候偏向了線程一的對象又有機會重新偏向線程二,即可以不用升級為輕量級鎖,可這和我們之前做的實驗矛盾了呀,其實要實現重新偏向是要有條件的:就是超過20對象對同一個線程如線程一撤銷偏向時,那麼第20個及以後的對象才可以將撤銷對線程一的偏向這個動作變為將第20個及以後的對象偏向線程二。

樂觀鎖VS悲觀鎖

樂觀鎖(無鎖)

CAS

優點

  • 不會出現阻塞,所有線程都處於競爭狀態,適用於線程較小的情況

缺點

  • 當線程較多的時候,會不斷自旋浪費cpu資源

多讀用樂觀鎖(衝突少)

多寫用悲觀鎖(衝突多)

從上面對兩種鎖的介紹,我們知道兩種鎖各有優缺點,不可認為一種好於另一種,像樂觀鎖適用於寫比較少的情況下(多讀場景),即衝突真的很少發生的時候,這樣可以省去了鎖的開銷,加大了系統的整個吞吐量。但如果是多寫的情況,一般會經常產生衝突,這就會導致上層應用會不斷的進行 retry,這樣反倒是降低了性能,所以一般多寫的場景下用悲觀鎖就比較合適。

公平鎖VS非公平鎖

公平鎖

公平鎖的優點是等待鎖的線程不會餓死。缺點是整體吞吐效率相對非公平鎖要低,等待隊列中除第一個線程以外的所有線程都會阻塞,CPU喚醒阻塞線程的開銷比非公平鎖大。

非公平鎖

非公平鎖的優點是可以減少喚起線程的開銷(比如新的線程D進來的時候剛好前邊的線程A釋放了鎖,那麼D可以直接獲取鎖,無需進入阻塞隊列),整體的吞吐效率高,因為線程有幾率不阻塞直接獲得鎖,CPU不必喚醒所有線程。缺點是處於等待隊列中的線程可能會餓死,或者等很久才會獲得鎖。

實現

ReentrantLock提供了公平和非公平鎖的實現。· 公平鎖:ReentrantLockpairLock =new ReentrantLock(true)。· 非公平鎖:ReentrantLockpairLock =new ReentrantLock(false)。

  • 如果構造函數不傳遞參數,則默認是非公平鎖

源碼比較

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

通過上圖中的源代碼對比,我們可以明顯的看出公平鎖與非公平鎖的lock()方法唯一的區別就在於公平鎖在獲取同步狀態時多了一個限制條件:hasQueuedPredecessors()。

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

再進入hasQueuedPredecessors(),可以看到該方法主要做一件事情:主要是判斷當前線程是否位於同步隊列中的第一個。如果是則返回true,否則返回false。

綜上,公平鎖就是通過同步隊列來實現多個線程按照申請鎖的順序來獲取鎖,從而實現公平的特性。非公平鎖加鎖時不考慮排隊等待問題,直接嘗試獲取鎖,所以存在後申請卻先獲得鎖的情況。

可重入鎖vs不可重入鎖

不可重入鎖可能會導致死鎖問題

首先ReentrantLock和NonReentrantLock都繼承父類AQS,其父類AQS中維護了一個同步狀態status來計數重入次數,status初始值為0。

當線程嘗試獲取鎖時,可重入鎖先嘗試獲取並更新status值,如果status == 0表示沒有其他線程在執行同步代碼,則把status置為1,當前線程開始執行。如果status != 0,則判斷當前線程是否是獲取到這個鎖的線程,如果是的話執行status+1,且當前線程可以再次獲取鎖。而非可重入鎖直接去獲取並嘗試更新當前status的值如果status != 0的話會導致其獲取鎖失敗,當前線程阻塞。

釋放鎖時,可重入鎖同樣先獲取當前status的值,在當前線程是持有鎖的線程的前提下。如果status-1 == 0,則表示當前線程所有重複獲取鎖的操作都已經執行完畢,然後該線程才會真正釋放鎖。而非可重入鎖則是在確定當前線程是持有鎖的線程之後,直接將status置為0,將鎖釋放。

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

鎖消除和鎖粗化

blog.csdn.net/qq_26222859…

鎖消除

鎖消除是發生在編譯器級別的一種鎖優化方式。
有時候我們寫的代碼完全不需要加鎖,卻執行了加鎖操作。

鎖消除是Java虛擬機在JIT編譯時,通過對運行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過鎖消除,可以節省毫無意義的請求鎖時間。

比如,stringbuffer類的append操作:

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}
複製代碼

從源碼中可以看出,append方法用了synchronized關鍵詞,它是線程安全的。但我們可能僅在線程內部把StringBuffer當作局部變量使用,比如:

    public static String test(String str1, String str2) {
        StringBuffer sb = new StringBuffer();
        sb.append(str1);
        sb.append(str2);
        return sb.toString();
    }
}
複製代碼

此時不同線程調用該方法,都會創建不同的stringbuffer對象,並不會出現鎖競爭等同步問題,所以此時編譯器會做優化,去除不可能存在共享資源競爭的鎖,這便是鎖消除。

鎖削除的主要判定依據來源於逃逸分析的數據支持,如果判斷到一段代碼中,在堆上的所有數據都不會逃逸出去被其他線程訪問到,那就可以把它們當作棧上數據對待,認為它們是線程私有的,同步加鎖自然就無須進行。

鎖粗化

public void doSomethingMethod(){
    synchronized(lock){
        //do some thing
    }
	//兩個加鎖過程中間,還有一些代碼,但執行的速度很快
    
    synchronized(lock){
        //do other thing
    }
}
複製代碼

這兩塊需要同步操作的代碼之間,需要做一些其它的工作,而這些工作只會花費很少的時間,那麼我們就可以把這些工作代碼放入鎖內,將兩個同步代碼塊合併成一個,以降低多次鎖請求、同步、釋放帶來的系統性能消耗,合併後的代碼如下:

public void doSomethingMethod(){
    //進行鎖粗化:整合成一次鎖請求、同步、釋放
    synchronized(lock){
        //do some thing
        //做其它不需要同步但能很快執行完的工作
        //do other thing
    }
}
複製代碼

手撕面答環節 -- 這是一條分割線

synchronized怎麼保證可見性?

  • 線程加鎖前,將清空工作內存中共享變量的值,從而使用共享變量時需要從主內存中重新讀取最新的值。
  • 線程加鎖後,其它線程無法獲取主內存中的共享變量。
  • 線程解鎖前,必須把共享變量的最新值刷新到主內存中

synchronized怎麼保證有序性?

synchronized同步的代碼塊,具有排他性,一次只能被一個線程擁有,所以synchronized保證同一時刻,代碼是單線程執行的。

因為as-if-serial語義的存在,單線程的程序能保證最終結果是有序的,但是不保證不會指令重排。

所以synchronized保證的有序是執行結果的有序性,而不是防止指令重排的有序性。

synchronized怎麼實現可重入的呢?

synchronized 是可重入鎖,也就是說,允許一個線程二次請求自己持有對象鎖的臨界資源,這種情況稱為可重入鎖。

synchronized 鎖對象的時候有個計數器,他會記錄下線程獲取鎖的次數,在執行完對應的代碼塊之後,計數器就會-1,直到計數器清零,就釋放鎖了。

之所以,是可重入的。是因為 synchronized 鎖對象有個計數器,會隨着線程獲取鎖後 +1 計數,當線程執行完畢後 -1,直到清零釋放鎖。

鎖升級?synchronized優化了解嗎?

Java對象頭裡,有一塊結構,叫Mark Word標記字段,這塊結構會隨着鎖的狀態變化而變化。

64 位虛擬機 Mark Word 是 64bit,我們來看看它的狀態變化:

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

Mark Word存儲對象自身的運行數據,如哈希碼、GC分代年齡、鎖狀態標誌、偏向時間戳(Epoch) 等。

  • 偏向鎖:在無競爭的情況下,只是在Mark Word里存儲當前線程指針,CAS操作都不做。
  • 輕量級鎖:在沒有多線程競爭時,相對重量級鎖,減少操作系統互斥量帶來的性能消耗。但是,如果存在鎖競爭,除了互斥量本身開銷,還額外有CAS操作的開銷。
  • 自旋鎖:減少不必要的CPU上下文切換。在輕量級鎖升級為重量級鎖時,就使用了自旋加鎖的方式
  • 鎖粗化:將多個連續的加鎖、解鎖操作連接在一起,擴展成一個範圍更大的鎖。
  • 鎖消除:虛擬機即時編譯器在運行時,對一些代碼上要求同步,但是被檢測到不可能存在共享數據競爭的鎖進行消除。

升級的具體過程

首先是無鎖,沒有競爭的情況

偏向鎖

再是偏向鎖,判斷是否可以偏向,查看線程ID是否為當前線程,是的話則直接執行,無需CAS

不是則CAS爭奪鎖,若成功則設置線程ID為自己 失敗,則升級為輕量級鎖

偏向鎖的撤銷

  1. 偏向鎖不會主動釋放(撤銷),只有遇到其他線程競爭時才會執行撤銷,由於撤銷需要知道當前持有該偏向鎖的線程棧狀態,因此要等到safepoint時執行,此時持有該偏向鎖的線程(T)有『2』,『3』兩種情況;
  2. 撤銷----T線程已經退出同步代碼塊,或者已經不再存活,則直接撤銷偏向鎖,變成無鎖狀態----該狀態達到閾值20則執行批量重偏向
  3. 升級----T線程還在同步代碼塊中,則將T線程的偏向鎖升級為輕量級鎖,當前線程執行輕量級鎖狀態下的鎖獲取步驟----該狀態達到閾值40則執行批量撤銷

輕量級鎖

  1. 進行加鎖操作時,jvm會判斷是否已經時重量級鎖,如果不是,則會在當前線程棧幀中划出一塊空間,作為該鎖的鎖記錄,並且將鎖對象MarkWord複製到該鎖記錄中
  2. 複製成功之後,jvm使用CAS操作將對象頭MarkWord更新為指向鎖記錄的指針,並將鎖記錄里的owner指針指向對象頭的MarkWord。如果成功,則執行『3』,否則執行『4』
  3. 更新成功,則當前線程持有該對象鎖,並且對象MarkWord鎖標誌設置為『00』,即表示此對象處於輕量級鎖狀態
  4. 更新失敗,jvm先檢查對象MarkWord是否指向當前線程棧幀中的鎖記錄,如果是則執行『5』,否則執行『6』
  5. 表示鎖重入;然後當前線程棧幀中增加一個鎖記錄第一部分(Displaced Mark Word)為null,並指向Mark Word的鎖對象,起到一個重入計數器的作用。
  6. 表示該鎖對象已經被其他線程搶佔,則進行自旋等待(默認10次),等待次數達到閾值仍未獲取到鎖,則升級為重量級鎖

升級過程:

聊聊Java中的鎖升級過程——無鎖>偏向鎖>輕量級鎖>重量級鎖 - 天天要聞

本篇屬於是冷麵大翻炒了,如有錯誤的地方還請指正

作者:Melo_
鏈接:https://juejin.cn/post/7160296578173894663

科技分類資訊推薦

全球最快、跑出全新試驗速度 中國高鐵再次衝上熱搜 - 天天要聞

全球最快、跑出全新試驗速度 中國高鐵再次衝上熱搜

為期三天的第十七屆中國國際現代化鐵路技術裝備展今天落幕,本屆展覽全球500餘家企業帶來了行業領先的技術和展品,記者在採訪中發現,中國高鐵技術全球領跑的優勢在持續擴大。3天的展期,4萬平方米的展覽面積,14個國家和地區的鐵路企業匯聚,展示了世界鐵路技術的最新成果,也讓中國高鐵再次衝上了熱搜。總台央視記者鄭連...
獲國家級認可!深圳這家醫院自主研發智慧養老評估系統入選國家推廣目錄 - 天天要聞

獲國家級認可!深圳這家醫院自主研發智慧養老評估系統入選國家推廣目錄

近日,工業和信息化部、民政部、國家衛生健康委員會聯合發佈了《智慧健康養老產品及服務推廣目錄(2024年版)》,深圳市第二人民醫院大鵬新區南澳醫院(南澳人民醫院)自主研發的「智慧老年人需求與綜合能力評估系統」脫穎而出,成功入選老年人能力評估類目錄,全國僅3例。這一系統的入選,標誌着南澳人民醫院在智慧養老領...
Manus跑路了嗎? - 天天要聞

Manus跑路了嗎?

衡宇 發自 凹非寺量子位 | 公眾號 QbitAIManus,真的從國內撤了?!4個月前一夜躥紅起飛的AI Agent產品Manus,剛被曝出背後公司一舉裁掉國內七成團隊。事實上,Manus總部已在5月搬到了新加坡,國內員工何去何從?現在答
美團:任何騎手學歷的總量數據都無事實依據 - 天天要聞

美團:任何騎手學歷的總量數據都無事實依據

IT之家 7 月 10 日消息,美團今日通過「小團有話說」公眾號對「丁 X 昭為什麼送外賣」進行回應:近期,短視頻賬號「丁 X 昭頻道」發佈多條身着美團騎手工服的視頻被廣泛關註:視頻中,丁 X 昭自述今年 39 歲,2004 年參加高考,是清華本科、北大與牛津雙碩士、南洋理工大學博士,曾任新加坡國立大學博士後研究員,目前在送...
潤滑鑄鋼魂 | 埃克森美孚中國攜創新方案助鋼鐵設備升級 - 天天要聞

潤滑鑄鋼魂 | 埃克森美孚中國攜創新方案助鋼鐵設備升級

在鋼鐵行業加速推進綠色低碳與智能化轉型的背景下,由中國設備管理協會冶金行業國際合作服務中心主辦的2025(第二屆)鋼鐵設備大會在張家港舉行。大會以「創新裂變·智驅未來」為主題,聚合政府部門、行業協會、研究機構及鋼鐵產業鏈上下游企業的眾多專業人士,共議冶金裝備在碳約束時代的技術突圍路徑與低碳發展範式。作為...
享界星享之夜耀啟新程:新標亮相,智造升級,用戶共鑒豪華新篇 - 天天要聞

享界星享之夜耀啟新程:新標亮相,智造升級,用戶共鑒豪華新篇

在汽車工業的百年變革中,中國新能源汽車正以智能化與高端化的姿態重新定義豪華。北汽集團與華為聯合打造的享界超級工廠,不僅是一座工廠,更是中國智造邁向全球價值鏈高端的宣言書。這座位於北京密雲區中關村科技園區的工廠,集成了20年豪華車製造經驗與尖端數字技術,每一台駛