JavaEE 【知識改變命運】03 多線程(3)

文章目錄

  • 多線程帶來的風險-線程安全
    • 線程不安全的舉例
    • 分析產出線程安全的原因:
      • 1.線程是搶占式的
      • 2. 多線程修改同一個變量(程序的要求)
      • 3. 原子性
      • 4. 內存可見性
      • 5. 指令重排序
    • 總結線程安全問題產生的原因
    • 解決線程安全問題
      • 1. synchronized關鍵字的介紹(監視器鎖 monitor lock)
        • a.鎖的概念
        • b.synchronized的特性
        • c.synchronized的用法
        • d.針對上述問題,加synchronied解決問題,分析底層邏輯
        • e.關于synchronized的總結
        • f.不同鎖對象的情況
        • g.如何判斷多個線程競爭的是不是同一把鎖
        • h.可重入鎖
        • I.鎖對象
  • Java 標準庫中的線程安全類
    • 不安全類
    • 安全類
  • volatile 關鍵字
    • 解決線程安全的問題
      • 內存可見性
      • 實例
      • CPU層面保證可見性
      • Java層面(保證指令順序,從而保證內存可見性)
      • 總結
  • wait() 和 notify()
    • wait和notify的基礎知識
    • wait()方法
    • notify()?法
    • notifyAll()?法
    • wait 和 sleep和join的對?(?試題)
    • wait和notify的總結

多線程帶來的風險-線程安全

線程不安全的舉例

場景: 用兩個線程對同一個變量分別自增5萬次,預期結果和自增結果是一個累加和,10萬次。

    public static  int count;public static void main(String[] args) {Counter counter = new Counter();Thread t1 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count();}});Thread t2 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Count: "+counter.count);}public  void count(){{count+=1;}} }

執行結果:

在這里插入圖片描述
程序運行得到的結果與預期的結果值不一樣,而且是一個錯誤的結果,而且我們程序的邏輯是正確的,這個現象所表現的問題稱為線程安全問題

分析產出線程安全的原因:

1.線程是搶占式的

線程是搶占執行的(執行順序是隨機的)
由于線程的執行順序無法為人控制,搶占式執行是造成線程安全問題的主要罪魁禍首,而且我們解決不了,完全是CPU自己調度,而且和CPU的核數有關

2. 多線程修改同一個變量(程序的要求)

單個線程修改同一個變量不會產生線程安全問題
多個線程修改不同的變量不會產生線程安全問題
多個線程修改同一個變量,會產生線程安全問題

3. 原子性

  • 什么是原?性
    我們把?段代碼想象成?個房間,每個線程就是要進?這個房間的?。如果沒有任何機制保證,A進?房間之后,還沒有出來;B 是不是也可以進?房間,打斷 A 在房間?的隱私。這個就是不具備原?性那我們應該如何解決這個問題呢?是不是只要給房間加?把鎖,A
    進去就把?鎖上,其他?是不是就進不來了。這樣就保證了這段代碼的原?性了。 有時也把這個現象叫做同步互斥,表?操作是互相排斥的。
  • ?條 java 語句不?定是原?的,也不?定只是?條指令 比如上面的:count++,對應的是多條CPU指令 1:從內存或者寄存器讀取count值 LOAD 2:執行自增 ADD 3:把計算結果寫回寄存器或者內存 STORE
  • 不保證原?性會給多線程帶來什么問題 如果?個線程正在對?個變量操作,中途其他線程插?進來了,如果這個操作被打斷了,結果就可能是錯誤的。 這點也和線程的搶占式調度密切相關. 如果線程不是 “搶占” 的, 就算沒有原?性, 也問題不?.
    在這里插入圖片描述

在這里插入圖片描述

4. 內存可見性

  • 什么是內存可見性 一個線程對共享變量進行了修改,其他線程能感知到變量修改后的值。
  • Java內存模型(JMM) java虛擬機規范定義了Java內存模型 ?的是屏蔽掉各種硬件和操作系統的內存訪問差異,以實現讓Java程序在各種平臺下都能達到?致的并發效果.
    在這里插入圖片描述
  • 分析Java內存模型
    1.工作內存和線程之間是一一對應的
    2.java的共享變量都在主內存里面,java線程線程首先從主內存讀取變量的值到自己的工作內存
    3.每個線程都有自己的工作內存,且線程工作內存直接是相互隔離的
    4.線程在工作內存修改完變量的值后,又從工作內存把變量的值刷回主內存里面。
    5.在以上執行count++操作,由于兩個線程在執行,每個線程都有自己的工作內存,且相互不可見,最終導致了線程安全問題。線程對共享變量的修改線程之間相互感知不到
  • 注意: 為什么整這么多內存? 實際并沒有這么多 “內存”. 這只是 Java 規范中的?個術語, 是屬于 “抽象” 的叫法,所謂的 “主內存” 才是真正硬件?度的 “內存”. ?所謂的 “?作內存”, 則是指 CPU 的寄存器和?速緩存 為啥要這么?煩的拷來拷去? 因為
    CPU 訪問??寄存器的速度以及?速緩存的速度, 遠遠超過訪問內存的速度(快了 3 - 4 個數量級,也就是?千倍,
    上萬倍).那為什么不全部用寄存器,原因很簡單,太貴了。
  • 關于JMM內存模型的面試題:JMM規定
    1.所以線程不直接修改主內存中的共享變量
    2.如果修改共享變量,需要把這個變量從主內存復制到自己的工作內存中,修改完之和再刷回主內存
    3.各個線程之間不能相互通信,做到了內存級別的線程隔離。

5. 指令重排序

1.什么是指令重排序 我們寫的代碼,在編譯之后可能與代碼對應的指令順序不同,這個過程就是指令重排序(JVM層面可能重排序,CPU執行指令也可能重排序)
1.一段代碼是這樣的 a.代陽去教室取英語書 b.代陽去食堂吃飯 c.代陽去教室去數學書 在單線程情況下,JVM,CPU指令集會對其優化,執行順序按a–c–b的方式執行,也是沒有問題,可以少跑一次教室,這就叫指令重排序
編譯器對于指令重排序的前提是 “保持邏輯不發?變化”. 這?點在單線程環境下?較容易判斷, 但是在多線程環境下就沒那么容易了,
多線程的代碼執?復雜程度更?, 編譯器很難在編譯階段對代碼的執?效果進?預測, 因此激進的重排序很容易導致優化后的邏輯和之前不等價

總結線程安全問題產生的原因

  1. 線程是搶占式執行的
  • CPU的調度問題,硬件層面,我們解決不了
  1. 多個線程修改同一個變量
  • 在真實業務場景中,使用多線程就是為了提升效率,在并發編成中這個需求是滿足的
  1. 原子性
  • 指令是在CPU上執行,怎么才能讓CPU在執行時實現原子性,這個可能可以解決
  1. 內存可見性
  • java層面應該可以解決,進程之間可以進行通信,那那么在線程中應該也有這樣的機制,讓線程在內存中也可以彼此感知
  1. 指令重排序
  • 對于代碼來說誰的優先級高,我們可以通過某種方式告訴編譯器,不要對我的代碼進行重排序
  1. 總結以上1,2我們不能改變,但是3,4,5我們可以進行改變,只要滿足3,4,5中的一條或者多條,線程安全問題就可以解決

解決線程安全問題

1. synchronized關鍵字的介紹(監視器鎖 monitor lock)

a.鎖的概念

比如線程A拿到了鎖,別的線程如果要執行被鎖住的代碼,那就要等到線程A釋放鎖之后,如果A沒有釋放鎖,那么別的線程只能阻塞等待,這個狀態就是BLOCK

b.synchronized的特性
  1. 互斥:synchronized會引起互斥效果,某個線程執行到某個對象的synchronized時,其他線程如果也執行到同一個對象sychronized就會阻塞等待
  2. 保證了原子性(通過加鎖實現)
  3. 保證了內存可見性(通過串行執行實現)
  4. 不保證有序性
c.synchronized的用法

修飾方法:

  1. 修飾非靜態方法:默認鎖對象是this(當前對象)
  2. 修飾靜態方法:默認鎖對象是本身類
    修飾代碼塊:
    可以充當鎖對象的是實例對象(new出來的對象,類對象,this)
d.針對上述問題,加synchronied解決問題,分析底層邏輯
    public synchronized void count(){ //  修飾代碼塊加鎖synchronized(this){ //            count+=1; //        }synchronized(this){count+=1;}} }

在這里插入圖片描述
如果修飾方法:其實把方法進行了串行化處理
如果修飾的是代碼塊:其實把修飾代碼塊的內容,進行了串行話處理。對于部分類似這種要修改共享變量的情況進行串行話,其他代碼模塊繼續并行執行,這樣就可以提高效率

畫圖分析:
在這里插入圖片描述
注意的點: t1釋放鎖之后,也可能第二次還是t1先于t2拿到鎖,因為線程是搶占式執行的,不一定是t2
由于線程在執行邏輯之前要拿到鎖,當拿到鎖時,上一個線程已經執行完所有的指令,并把修改的值刷新會主內存,所有當前線程永遠讀到的是上一個線程執行完后的值

synchronized保證了原子性
因為當前線程永遠拿到的是前一個線程修改后的值,所有這樣也現象上實現了內存可見性,但是并沒有真正對內存可見性做出技術上的處理。
synchronized沒有保證有序性(不會禁止指令重排序)

e.關于synchronized的總結
  1. 被synchronized修身的代碼塊會編成串行執行
  2. synchronized可以修飾方法或者代碼塊
  3. 被修飾的代碼并不是一次性在CPU執行完,而是中途可能會被CPU調度走,當所有指令執行完后才會釋放鎖
  4. 只給一個線程加鎖,也會出現線程安全
f.不同鎖對象的情況
  1. 同·一個引用調用(靜態和非靜態)兩個方法(一個用synchronized修飾一個不用synchronized不修飾)只加一把鎖
public static  int count;public  static void main(String[] args) {Counter_Demo1 counter = new Counter_Demo1();Thread t1 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count();}});Thread t2 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count1();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Count: "+counter.count);}public  void count(){//修飾非靜態代碼塊synchronized(this){count+=1;}}public  void count1(){{count+=1;}}
//修飾非靜態方法    
//    public void synchronized count(){
//         {
//            count+=1;
//        }
//    }
//    public  void count1(){
//        {
//            count+=1;
//        }
//    }
修飾靜態的方法和代碼塊
//    public static void count(){
//        //修飾代碼塊
//        //靜態方法里面不能用this
//        synchronized(Counter_Demo1.class){
//            count+=1;
//        }
//    }
//    public static void count1(){
//        {
//            count+=1;
//        }
//    }
//    public synchronized static void count(){
//        //修飾代碼塊
//        //靜態方法里面不能用this
//        {
//            count+=1;
//        }
//    }
//    public static void count1(){
//        {
//            count+=1;
//        }
//    }

執行結果
都不符合預期
在這里插入圖片描述

  1. 兩個引用調用同一個方法(鎖對象是實例對象new)
 public static  int count;public  static void main(String[] args) {Counter_Demo1 counter1 = new Counter_Demo1();Counter_Demo1 counter2 = new Counter_Demo1();Thread t1 =new Thread(()->{for(int i=0;i<5_0000;i++){counter1.count();}});Thread t2 =new Thread(()->{for(int i=0;i<5_0000;i++){counter2.count();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Count: "+counter1.count);}Object object=new Object();public void count(){synchronized (object){count+=1;}}

執行結果不符合預期
在這里插入圖片描述
用類對象來加鎖

static Object  object= new Object();public void count(){synchronized (object){count+=1;}}

執行結果符合預期
在這里插入圖片描述
結論:

  1. 只要一個線程A獲得鎖,沒有鎖競爭
  2. 線程A和線程B共同搶一把鎖,誰先拿到鎖就先執行誰,另一個線程就要阻塞等待,等到持有鎖的線程釋放鎖之后再競爭鎖
  3. 線程A與線程B搶的不是同一把鎖,它們之間沒有競爭關系,分別去拿到自己的鎖,不存在鎖關系
g.如何判斷多個線程競爭的是不是同一把鎖
  1. 實例對象:new出來的對象,每個都是單獨存在
  2. 類中的屬性:類沒有用static修飾的變量,每個實例對象都是不同的
  3. 類中的靜態成員變量:用static修飾,屬于類對象,全局唯一
  4. 類對象:.class文件加載jvm之后的對象,全局唯一
  5. 線程之間是否存在鎖競爭,關鍵是看訪問的是不是同一個鎖對象,如果是則存在鎖競爭,如果不是則不存在鎖競爭
h.可重入鎖
  • 對同一個鎖對象和同一個線程,如果可以重復加鎖,稱之為不互斥,稱之為可重入。
  • 對同一個鎖對象和同一線程,如果不可以重復加鎖,稱之為互斥,就會形成死鎖。
  • 已經獲取鎖對象的線程,如果再多次進行加鎖操作,不會產生互斥現象
    在這里插入圖片描述
I.鎖對象
  • 鎖對象記錄了獲取鎖的線程信息
  • 任何對象都可以做鎖對象
  • java中每個對象都是由以下幾個部分組成:
    – 1.markword
    – 2.類型指針
    – 3.實例數據
    – 4.對齊填充
    – 5對象默認帶線啊哦是16byte
    在這里插入圖片描述
    在這里插入圖片描述

Java 標準庫中的線程安全類

不安全類

  • Arraylist
  • LinkedList
  • HashMap
  • TreeMap
  • HashSet
  • TreeSet
  • StringBuilder

安全類

-Vector(不推薦)

  • HashTable(不推薦)

  • CocurrentHashMap

  • StringBuffer

  • String (雖然沒有加鎖,但是不涉及修飾仍然是線程安全的)

volatile 關鍵字

解決線程安全的問題

  • 真正意義上解決了內存可見性
  • 解決了指令重排序(禁止指令重排序)問題
  • 沒有解決原子性問題

內存可見性

  • 我們都知道,實際工作時候,訪問的數據都是工作內存里面的數據,這樣是為了保證效率,但是這樣有時候會產生安全問題。但是加上 volatile , 強制讀寫內存. 速度是慢了, 但是數據變的更準確了
  • 代碼在寫? volatile 修飾的變量的時候
    – 改變線程?作內存中volatile變量副本的值
    – 將改變后的副本的值從?作內存刷新到主內存
  • 代碼在讀取volatile修改的變量時候
    –從主內存中讀取volatile變量的最新值到線程的?作內存中
    –從?作內存中讀取volatile變量的副本

實例

static class Counter {public volatile int flag = 0;}public static void main(String[] args) {Counter counter = new Counter();Thread t1 = new Thread(() -> {while (counter.flag == 0) {// do nothing}System.out.println("循環結束!");});Thread t2 = new Thread(() -> {Scanner scanner = new Scanner(System.in);System.out.println("輸??個整數:");counter.flag = scanner.nextInt();});t1.start();t2.start();}
// 執?效果
// 當??輸??0值時, t1 線程循環不會結束. (這顯然是?個 bug)
//static class Counter {
//    public volatile int flag = 0;
//}
// 執?效果
// 當??輸??0值時, t1 線程循環能夠?即結束.

在這里插入圖片描述

  • 對于線程t1來說,只是比較flag這個變量的值,從來都沒有修改過,所有認為,這個值永遠也不會改變,從而也不會重新從主內存中讀取值(cpu為了提升高運行效率這個值一般存在寄存器或者cpu的緩存中)

  • 在多線程環境下,就會出現出現這個問題,一個線程修改了另一個線程無法感知到的變量

CPU層面保證可見性

MESI緩存 一致協議(可以理解是一種通知機制)
在這里插入圖片描述

Java層面(保證指令順序,從而保證內存可見性)

內存屏障:作用是保證指令執行的順序,從而保證內存可見性
在這里插入圖片描述
volatile寫:
在這里插入圖片描述
volatile讀:
在這里插入圖片描述
有序性:用volatile 修改過的變量,由于前后有內存屏障,保證了指令的執行順序,也可以理解為告訴編譯器,不要進行指令重排序。

總結

volatile不保證原子性

public static volatile int count;public synchronized static void main(String[] args) {Counter counter = new Counter();Thread t1 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count();}});Thread t2 =new Thread(()->{for(int i=0;i<5_0000;i++){counter.count();}});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Count: "+counter.count);}public  void count(){count+=1;}

在這里插入圖片描述

volatile保證可見性:MESI緩存 一致協議(可以理解是一種通知機制)
volatile保證有序性:內存屏障:作用是保證指令執行的順序,從而保證內存可見性

wait() 和 notify()

wait和notify的基礎知識

  • wait() 和notify(),notifyAll()是object方法
  • wait()/wait(long timeout):讓線程進入等待的線程
  • notify()/notifyAll():喚醒在當前對象上等待的線程

wait()方法

  • wait做的事情
    – 使當前執行代碼的線程進行等待(把線程放到等待隊列中)
    – 釋放當前鎖
    – 滿足一定條件被喚醒,嘗試重新獲得這個鎖
    – wait要搭配sychronized來使用,脫離sychronized使用wait會之間拋出異常
  • wait 結束等待的條件:
    – 其他線程調用 調用該對象的notify方法
    – wait等待時間超時(wait ?法提供?個帶有 timeout 參數的版本, 來指定等待時間)
    – 其他線程調用該等待線程的interrupted方法,導致wait拋出InterruptedException 異常.
  • wait()方法代碼使用
public static void main(String[] args) throws InterruptedException {Object object = new Object();System.out.println("等待中");synchronized (object) {object.wait(1000);}System.out.println("等待結束");}這樣在執?到object.wait()之后就?直等待下去,那么程序肯定不能?直這么等待下去了。這個時候就
需要使?到了另外?個?法喚醒的?法notify()

notify()?法

  • notify ?法是喚醒等待的線程.
    – 方法notify()也要在同步方法或者同步代碼塊中執行,該方法是用來通知哪些可能等待該對象的對象鎖的其他線程,對其發出通知,并使它們重新獲取該對象對象鎖
    – 如果由多個線程等待,則有線程調度器隨機挑選出一個呈現wait狀態的線程。(并沒有 “先來后到”))
    – 在notify()方法后,當前線程不會立馬釋放該對象鎖,需要等到notify方法線程將程序執行完,也就是退出同步代碼塊之后才會釋放鎖對象。
  • 使用notify()方法喚醒線程
static class WaitTask implements Runnable  {private Object locker;public WaitTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker){try {System.out.println("等待開始") ;locker.wait();System.out.println("等待結束");} catch (InterruptedException e) {e.printStackTrace();}}}}static class NotifyTask implements Runnable {private Object locker;public NotifyTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker) {System.out.println("notify 開始");locker.notify();System.out.println("notify 結束");}}}public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(new WaitTask(locker));Thread t2 = new Thread(new NotifyTask(locker));t1.start();Thread.sleep(1000);t2.start();}

notifyAll()?法

  • notify?法只是喚醒某?個等待線程. 使?notifyAll?法可以?次喚醒所有的等待線程.
 static class WaitTask implements Runnable {private Object locker;public WaitTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker) {try {System.out.println("等待開始");locker.wait();System.out.println("等待結束");} catch (InterruptedException e) {e.printStackTrace();}}}}static class NotifyTask implements Runnable {private Object locker;public NotifyTask(Object locker) {this.locker = locker;}@Overridepublic void run() {synchronized (locker) {System.out.println("notify 開始");locker.notifyAll();System.out.println("notify 結束");}}}public static void main(String[] args) throws InterruptedException {Object locker = new Object();Thread t1 = new Thread(new WaitTask(locker));Thread t3 = new Thread(new WaitTask(locker));Thread t4 = new Thread(new WaitTask(locker));Thread t2 = new Thread(new NotifyTask(locker));t1.start();t3.start();t4.start();sleep(1000);t2.start();}}

注意: 雖然是同時喚醒 3 個線程, 但是這 3 個線程需要競爭鎖. 所以并不是同時執?, ?仍然是有先有后的執?

wait 和 sleep和join的對?(?試題)

  1. wait需要搭配synchronized使用 sleep,join不需要
  2. wait是Object的方法,sleep是Thread的靜態方法,join是類中的方法(實例方法)
  3. 一個是用于線程之間的通信的,兩個是讓線程阻塞一段時間
  4. 相同點:可以讓線程放棄執行一段時間

wait和notify的總結

在這里插入圖片描述

  • join和wait是兩個不同的操作
    –join是Thread類中的方法
    – wait和notify是Object類中的方法
    – join狀態,主線程要等待子線程的結果
    – wait是等待另一個線程的資源
  • wait和notify必須跟synchronized一起使用,并且使用同一個對象
    – 否則會報錯
    在這里插入圖片描述
    – wait的線程進入阻塞狀態,調用wait的線程會釋放自己持有的鎖(不再占有cpu資源)
  • notify()和notifyAll(),
    – notify隨機喚醒一個線程,notifyAll喚醒所有線程,喚醒后的線程需要重新去競爭鎖,拿到鎖之后wait位置的代碼才會繼續執行。
  • 使用小結
    – wait和notify必須搭配synchronized一起使用
    – wait和notify使用的鎖對象必須是同一個
    – notify執行多少次都沒有關系(及時沒有wait)(類似老板把包子做好空喊了一聲)
  • 舉例:
    – 現實舉例:在這里插入圖片描述
    – 指令舉例
    在這里插入圖片描述

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

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

相關文章

并發在前端中的應用?

?并發在前端中的應用主要體現在處理多個請求和優化頁面加載速度方面?。前端并發處理通常涉及在極短時間內發送多個數據請求&#xff0c;例如在頁面渲染時同時請求多個數據。通過并發處理&#xff0c;可以顯著減少頁面加載時間&#xff0c;提升用戶體驗。 前端并發處理的具體…

【力扣】409.最長回文串

問題描述 思路解析 因為同時包含大小寫字母&#xff0c;直接創建個ASCII表大小的桶來標記又因為是要回文子串&#xff0c;所以偶數個數的一定可以那么同時&#xff0c;對于出現奇數次數的&#xff0c;我沒需要他們的次數-1&#xff0c;變為偶數&#xff0c;并且可以標記出現過…

計算機視覺在科學研究(數字化)中的實際應用

計算機視覺是一種利用計算機技術來解析和理解圖像和視頻的方法。.隨著計算機技術的不斷發展&#xff0c;計算機視覺被廣泛應用于科學研究領域&#xff0c;為科學家提供了無限的可能。 一、生命科學領域 在生命科學領域&#xff0c;計算機視覺被廣泛用于圖像識別、分類和測量等…

springboot381銀行客戶管理系統(論文+源碼)_kaic

摘 要 伴隨著信息技術與互聯網技術的不斷發展&#xff0c;人們進到了一個新的信息化時代&#xff0c;傳統管理技術性沒法高效率、容易地管理信息內容。為了實現時代的發展必須&#xff0c;提升管理高效率&#xff0c;各種各樣管理管理體系應時而生&#xff0c;各個領域陸續進到…

JMX 組件架構即詳解

JMX架構由三個主要組件構成&#xff1a; ?MBeans&#xff08;Managed Beans&#xff09;?&#xff1a;代表可管理的資源&#xff0c;是JMX的核心。MBean可以是Java類或接口&#xff0c;提供了管理操作的接口&#xff0c;如獲取系統信息、設置參數等。?MBeanServer?&#x…

LLMs之ICL:《Bayesian scaling laws for in-context learning》翻譯與解讀

LLMs之ICL&#xff1a;《Bayesian scaling laws for in-context learning》翻譯與解讀 導讀&#xff1a;這篇論文的核心議題是理解和建模大型語言模型&#xff08;LLM&#xff09;的上下文學習&#xff08;ICL&#xff09;能力。文章從貝葉斯學習的角度出發&#xff0c;提出了一…

基于單片機和測頻法的頻率計設計及proteus仿真

摘要: 傳感器廣泛應用在自動化測量中,該文利用 51 單片機 2 個 16 位定時器和測量頻率中的測頻法設計了測量方波的頻率計,并用LCD1602 液晶顯示頻率、 proteus 仿真,測試結果表明設計思路正確、誤差小。 關鍵詞: 單片機;測頻法;頻率計; proteus 1 概述 傳感器能感受到…

軟件漏洞印象

軟件漏洞印象 軟件安全性檢測 軟件安全靜態分析&#xff1a;學術界一度十分熱衷的偏理論性方法軟件漏洞動態挖掘&#xff0c;工程界普遍采用動態漏洞挖掘方式&#xff0c;即Fuzz技術&#xff0c;也稱為模糊測試 漏洞利用 vs. 漏洞修復 對于已發現的軟件漏洞 黑客會基于Meta…

計算機網絡 —— HTTPS 協議

前一篇文章&#xff1a;計算機網絡 —— HTTP 協議&#xff08;詳解&#xff09;-CSDN博客 目錄 前言 一、HTTPS 協議簡介 二、HTTPS 工作過程 1.對稱加密 2.非對稱加密 3.中間人攻擊 4.引入證書 三、HTTPS 常見問題 1.中間人能否篡改證書&#xff1f; 2.中間人能否調…

定點數的乘除運算

原碼一位乘法 乘積的符號由兩個數的符號位異或而成。&#xff08;不參與運算&#xff09;被乘數和乘數均取絕對值參與運算&#xff0c;看作無符號數。乘數的最低位為Yn&#xff1a; 若Yn1&#xff0c;則部分積加上被乘數|x|&#xff0c;然后邏輯右移一位&#xff1b;若Yn0&…

如何設置ChromeDriver路徑?

設置ChromeDriver路徑是為了讓Selenium能夠正確地調用Chrome瀏覽器進行自動化操作。以下是幾種設置ChromeDriver路徑的方法&#xff1a; 1. 系統環境變量 將ChromeDriver的路徑添加到系統的環境變量中&#xff0c;這樣在任何地方都可以直接調用ChromeDriver。 Windows系統&a…

數據挖掘:一、Weka軟件的基本操作

實驗目的和要求 了解Weka軟件的使用 實驗環境 Windows11 Weka3.8.6 實驗內容與過程 實驗內容 1、了解Weka使用的一般步驟 2、利用Weka,對數據集進行關聯規則挖掘及數據分類 3、記錄操作步驟、使用的數據、最終的結果 實驗過程 首先打開weka下載官網,選擇合適

【從零開始的LeetCode-算法】383. 贖金信

給你兩個字符串&#xff1a;ransomNote 和 magazine &#xff0c;判斷 ransomNote 能不能由 magazine 里面的字符構成。 如果可以&#xff0c;返回 true &#xff1b;否則返回 false 。 magazine 中的每個字符只能在 ransomNote 中使用一次。 示例 1&#xff1a; 輸入&#…

【第二十四周】從大語言模型到多模態大模型的發展

摘要 大語言模型&#xff08;Large Language Model, LLM&#xff09;是指一類基于深度學習的人工智能系統&#xff0c;它們被設計用來理解和生成自然語言。這些模型通常是在大量的文本數據上進行訓練的&#xff0c;通過學習文本中的模式和結構&#xff0c;它們能夠執行各種各樣…

https ssl免費證書申請,自動續期,acme、certd

本文為個人筆記&#xff0c;方便自己需要時查閱&#xff0c;同時提供出來給大家作為免費ssl證書自動續簽需求的一種參考 大部分免費證書的有效期僅有3個月&#xff0c;所以證書管理會涉及到自動續期管理的問題 一、acme證書 大佬們常用的證書證書申請管理方式&#xff0c;提…

uniapp的生命周期

在 UniApp 中&#xff0c;生命周期函數是指在組件&#xff08;如頁面、視圖等&#xff09;創建和銷毀過程中會自動觸發的一些函數。UniApp 提供了多種生命周期函數&#xff0c;幫助開發者在適當的時機進行相關的邏輯處理。 UniApp 的生命周期函數可以分為 頁面生命周期 和 組件…

unity打包到安卓幀率降低

這個問題遇到過很多次了我的做法就是直接設置Application.targetFrameRate60 參考

【Vue】v-model、ref獲取DOM

目錄 v-moel v-model的原理 v-model用在組件標簽上 方式 defineModel()簡寫 ref屬性 獲取原生DOM 獲取組件實例 nextTick() v-moel v-model&#xff1a;雙向數據綁定指令 數據變了&#xff0c;視圖跟著變&#xff08;數據驅動視圖&#xff09;視圖變了&#xff0c;數…

Kubernetes 常用操作大全:全面掌握 K8s 基礎與進階命令

Kubernetes&#xff08;簡稱 K8s&#xff09;作為一種開源的容器編排工具&#xff0c;已經成為現代分布式系統中的標準。它的強大之處在于能夠自動化應用程序的部署、擴展和管理。在使用 Kubernetes 的過程中&#xff0c;熟悉常用操作對于高效地管理集群資源至關重要。本文將詳…

sqlmap --os-shell的原理(MySQL,MSSQL,PostgreSQL,Oracle,SQLite)

1. MySQL 條件 數據庫用戶需要具備高權限&#xff08;如 FILE 權限&#xff09;。數據庫服務運行用戶需要對目標目錄有寫權限。Web 服務器有可寫目錄&#xff0c;且支持執行上傳的腳本&#xff08;如 PHP、JSP 等&#xff09;。 原理 利用 MySQL 的 SELECT ... INTO OUTFIL…