国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

ThreadLocal的作用以及應(yīng)用場景

倩倩 ? 來源:juejin.cn ? 作者:芋道源碼 ? 2022-09-19 10:56 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群


ThreadLocal的作用以及應(yīng)用場景

ThreadLocal算是一種并發(fā)容器吧,因為他的內(nèi)部是有ThreadLocalMap組成,ThreadLocal是為了解決多線程情況下變量不能被共享的問題,也就是多線程共享變量的問題。

ThreadLocalLock以及Synchronized的區(qū)別是:ThreadLocal是給每個線程分配一個變量(對象),各個線程都存有變量的副本,這樣每個線程都是使用自己(變量)對象實例,使線程與線程之間進(jìn)行隔離;而LockSynchronized的方式是使線程有順序的執(zhí)行。

舉一個簡單的例子:目前有100個學(xué)生等待簽字,但是老師只有一個筆,那老師只能按順序的分給每個學(xué)生,等待A學(xué)生簽字完成然后將筆交給B學(xué)生,這就類似LockSynchronized的方式。而ThreadLocal是,老師直接拿出一百個筆給每個學(xué)生;再效率提高的同事也要付出一個內(nèi)存消耗;也就是以空間換時間的概念

基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

使用場景

Spring的事務(wù)隔離就是使用ThreadLocal和AOP來解決的;主要是TransactionSynchronizationManager這個類;

解決SimpleDateFormat線程不安全問題;

當(dāng)我們使用SimpleDateFormatparse()方法的時候,parse()方法會先調(diào)用Calendar.clear()方法,然后調(diào)用Calendar.add()方法,如果一個線程先調(diào)用了add()方法,然后另一個線程調(diào)用了clear()方法;這時候parse()方法就會出現(xiàn)解析錯誤;如果不信我們可以來個例子:

publicclassSimpleDateFormatTest{

privatestaticSimpleDateFormatsimpleDateFormat=newSimpleDateFormat("yyyy-MM-dd");

publicstaticvoidmain(String[]args){
for(inti=0;i50;i++){
Threadthread=newThread(newRunnable(){
@Override
publicvoidrun(){
dateFormat();
}
});
thread.start();
}
}

/**
*字符串轉(zhuǎn)成日期類型
*/
publicstaticvoiddateFormat(){
try{
simpleDateFormat.parse("2021-5-27");
}catch(ParseExceptione){
e.printStackTrace();
}
}
}

這里我們只啟動了50個線程問題就會出現(xiàn),其實看巧不巧,有時候只有10個線程的情況就會出錯:

Exceptioninthread"Thread-40"java.lang.NumberFormatException:Forinputstring:""
atjava.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
atjava.lang.Long.parseLong(Long.java:601)
atjava.lang.Long.parseLong(Long.java:631)
atjava.text.DigitList.getLong(DigitList.java:195)
atjava.text.DecimalFormat.parse(DecimalFormat.java:2084)
atjava.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
atjava.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
atjava.text.DateFormat.parse(DateFormat.java:364)
atcn.haoxy.use.lock.sdf.SimpleDateFormatTest.dateFormat(SimpleDateFormatTest.java:36)
atcn.haoxy.use.lock.sdf.SimpleDateFormatTest$1.run(SimpleDateFormatTest.java:23)
atjava.lang.Thread.run(Thread.java:748)
Exceptioninthread"Thread-43"java.lang.NumberFormatException:multiplepoints
atsun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
atsun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
atjava.lang.Double.parseDouble(Double.java:538)
atjava.text.DigitList.getDouble(DigitList.java:169)
atjava.text.DecimalFormat.parse(DecimalFormat.java:2089)
atjava.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
atjava.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
atjava.text.DateFormat.parse(DateFormat.java:364)
at.............

其實解決這個問題很簡單,讓每個線程new一個自己的SimpleDateFormat,但是如果100個線程都要new100個SimpleDateFormat嗎?

當(dāng)然我們不能這么做,我們可以借助線程池加上ThreadLocal來解決這個問題:

publicclassSimpleDateFormatTest{

privatestaticThreadLocallocal=newThreadLocal(){
@Override
//初始化線程本地變量
protectedSimpleDateFormatinitialValue(){
returnnewSimpleDateFormat("yyyy-MM-dd");
}
};

publicstaticvoidmain(String[]args){
ExecutorServicees=Executors.newCachedThreadPool();
for(inti=0;i500;i++){
es.execute(()->{
//調(diào)用字符串轉(zhuǎn)成日期方法
dateFormat();
});
}
es.shutdown();
}
/**
*字符串轉(zhuǎn)成日期類型
*/
publicstaticvoiddateFormat(){
try{
//ThreadLocal中的get()方法
local.get().parse("2021-5-27");
}catch(ParseExceptione){
e.printStackTrace();
}
}
}

這樣就優(yōu)雅的解決了線程安全問題;

解決過度傳參問題;例如一個方法中要調(diào)用好多個方法,每個方法都需要傳遞參數(shù);例如下面示例:

voidwork(Useruser){
getInfo(user);
checkInfo(user);
setSomeThing(user);
log(user);
}

用了ThreadLocal之后:

publicclassThreadLocalStu{

privatestaticThreadLocaluserThreadLocal=newThreadLocal<>();

voidwork(Useruser){
try{
userThreadLocal.set(user);
getInfo();
checkInfo();
someThing();
}finally{
userThreadLocal.remove();
}
}

voidsetInfo(){
Useru=userThreadLocal.get();
//.....
}

voidcheckInfo(){
Useru=userThreadLocal.get();
//....
}

voidsomeThing(){
Useru=userThreadLocal.get();
//....
}
}

每個線程內(nèi)需要保存全局變量(比如在登錄成功后將用戶信息存到ThreadLocal里,然后當(dāng)前線程操作的業(yè)務(wù)邏輯直接get取就完事了,有效的避免的參數(shù)來回傳遞的麻煩之處),一定層級上減少代碼耦合度。

  • 比如存儲 交易id等信息。每個線程私有。
  • 比如aop里記錄日志需要before記錄請求id,end拿出請求id,這也可以。
  • 比如jdbc連接池(很典型的一個ThreadLocal用法)
  • ....等等....

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

原理分析

上面我們基本上知道了ThreadLocal的使用方式以及應(yīng)用場景,當(dāng)然應(yīng)用場景不止這些這只是工作中常用到的場景;下面我們對它的原理進(jìn)行分析;

我們先看一下它的set()方法;

publicvoidset(Tvalue){
Threadt=Thread.currentThread();
ThreadLocalMapmap=getMap(t);
if(map!=null)
map.set(this,value);
else
createMap(t,value);
}

是不是特別簡單,首先獲取當(dāng)前線程,用當(dāng)前線程作為key,去獲取ThreadLocalMap,然后判斷map是否為空,不為空就將當(dāng)前線程作為key,傳入的value作為map的value值;如果為空就創(chuàng)建一個ThreadLocalMap,然后將key和value方進(jìn)去;從這里可以看出value值是存放到ThreadLocalMap中;

然后我們看看ThreadLocalMap是怎么來的?先看下getMap()方法:

//在Thread類中維護(hù)了threadLocals變量,注意是Thread類
ThreadLocal.ThreadLocalMapthreadLocals=null;

//在ThreadLocal類中的getMap()方法
ThreadLocalMapgetMap(Threadt){
returnt.threadLocals;
}

這就能解釋每個線程中都有一個ThreadLocalMap,因為ThreadLocalMap的引用在Thread中維護(hù);這就確保了線程間的隔離;

我們繼續(xù)回到set()方法,看到當(dāng)map等于空的時候createMap(t, value);

voidcreateMap(Threadt,TfirstValue){
t.threadLocals=newThreadLocalMap(this,firstValue);
}

這里就是new了一個ThreadLocalMap然后賦值給threadLocals成員變量;ThreadLocalMap構(gòu)造方法:

ThreadLocalMap(ThreadLocalfirstKey,ObjectfirstValue){
//初始化一個Entry
table=newEntry[INITIAL_CAPACITY];
//計算key應(yīng)該存放的位置
inti=firstKey.threadLocalHashCode&(INITIAL_CAPACITY-1);
//將Entry放到指定位置
table[i]=newEntry(firstKey,firstValue);
size=1;
//設(shè)置數(shù)組的大小16*2/3=10,類似HashMap中的0.75*16=12
setThreshold(INITIAL_CAPACITY);
}

這里寫有個大概的印象,后面對ThreadLocalMap內(nèi)部結(jié)構(gòu)還會進(jìn)行詳細(xì)的講解;

下面我們再去看一下get()方法:

publicTget(){
Threadt=Thread.currentThread();
//用當(dāng)前線程作為key去獲取ThreadLocalMap
ThreadLocalMapmap=getMap(t);
if(map!=null){
//map不為空,然后獲取map中的Entry
ThreadLocalMap.Entrye=map.getEntry(this);
if(e!=null){
@SuppressWarnings("unchecked")
//如果Entry不為空就獲取對應(yīng)的value值
Tresult=(T)e.value;
returnresult;
}
}
//如果map為空或者entry為空的話通過該方法初始化,并返回該方法的value
returnsetInitialValue();
}

get()方法和set()都比較容易理解,如果map等于空的時候或者entry等于空的時候我們看看setInitialValue()方法做了什么事:

privateTsetInitialValue(){
//初始化變量值由子類去實現(xiàn)并初始化變量
Tvalue=initialValue();
Threadt=Thread.currentThread();
//這里再次getMap();
ThreadLocalMapmap=getMap(t);
if(map!=null)
map.set(this,value);
else
//和set()方法中的
createMap(t,value);
returnvalue;
}

下面我們再去看一下ThreadLocal中的initialValue()方法:

protectedTinitialValue(){
returnnull;
}

設(shè)置初始值,由子類去實現(xiàn);就例如我們上面的例子,重寫ThreadLocal類中的initialValue()方法:

privatestaticThreadLocallocal=newThreadLocal(){
@Override
//初始化線程本地變量
protectedSimpleDateFormatinitialValue(){
returnnewSimpleDateFormat("yyyy-MM-dd");
}
};

createMap()方法和上面set()方法中createMap()方法同一個,就不過多的敘述了;剩下還有一個removve()方法

publicvoidremove(){
ThreadLocalMapm=getMap(Thread.currentThread());
if(m!=null)
//2.從map中刪除以當(dāng)前threadLocal實例為key的鍵值對
m.remove(this);
}

源碼的講解就到這里,也都比較好理解,下面我們看看ThreadLocalMap的底層結(jié)構(gòu)

ThreadLocalMap的底層結(jié)構(gòu)

上面我們已經(jīng)了解了ThreadLocal的使用場景以及它比較重要的幾個方法;下面我們再去它的內(nèi)部結(jié)構(gòu);經(jīng)過上的源碼分析我們可以看到數(shù)據(jù)其實都是存放到了ThreadLocal中的內(nèi)部類ThreadLocalMap中;而ThreadLocalMap中又維護(hù)了一個Entry對象,也就說數(shù)據(jù)最終是存放到Entry對象中的;

staticclassThreadLocalMap{

staticclassEntryextendsWeakReference<ThreadLocal>{
/**ThevalueassociatedwiththisThreadLocal.*/
Objectvalue;

Entry(ThreadLocalk,Objectv){
super(k);
value=v;
}

}
ThreadLocalMap(ThreadLocalfirstKey,ObjectfirstValue){
table=newEntry[INITIAL_CAPACITY];
inti=firstKey.threadLocalHashCode&(INITIAL_CAPACITY-1);
table[i]=newEntry(firstKey,firstValue);
size=1;
setThreshold(INITIAL_CAPACITY);
}
//....................
}

Entry的構(gòu)造方法是以當(dāng)前線程為key,變量值Object為value進(jìn)行存儲的;在上面的源碼中ThreadLocalMap的構(gòu)造方法中也涉及到了Entry;看到Entry是一個數(shù)組;初始化長度為INITIAL_CAPACITY = 16;因為 Entry 繼承了 WeakReference,在 Entry 的構(gòu)造方法中,調(diào)用了 super(k)方法就會將 threadLocal 實例包裝成一個 WeakReferenece。這也是ThreadLocal會產(chǎn)生內(nèi)存泄露的原因;

內(nèi)存泄露產(chǎn)生的原因

a6f698ac-37c4-11ed-ba43-dac502259ad0.png

如圖所示存在一條引用鏈: Thread Ref->Thread->ThreadLocalMap->Entry->Key:Value,經(jīng)過上面的講解我們知道ThreadLocal作為Key,但是被設(shè)置成了弱引用,弱引用在JVM垃圾回收時是優(yōu)先回收的,就是說無論內(nèi)存是否足夠弱引用對象都會被回收;弱引用的生命周期比較短;當(dāng)發(fā)生一次GC的時候就會變成如下:

a724c54c-37c4-11ed-ba43-dac502259ad0.png

TreadLocalMap中出現(xiàn)了Key為null的Entry,就沒有辦法訪問這些key為null的Entry的value,如果線程遲遲不結(jié)束(也就是說這條引用鏈無意義的一直存在)就會造成value永遠(yuǎn)無法回收造成內(nèi)存泄露;如果當(dāng)前線程運行結(jié)束Thread,ThreadLocalMap,Entry之間沒有了引用鏈,在垃圾回收的時候就會被回收;但是在開發(fā)中我們都是使用線程池的方式,線程池的復(fù)用不會主動結(jié)束;所以還是會存在內(nèi)存泄露問題;

解決方法也很簡單,就是在使用完之后主動調(diào)用remove()方法釋放掉;

解決Hash沖突

記得在大學(xué)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的時候?qū)W習(xí)了很多種解決hash沖突的方法;例如:

線性探測法(開放地址法的一種): 計算出的散列地址如果已被占用,則按順序找下一個空位。如果找到末尾還沒有找到空位置就從頭重新開始找;

a7660520-37c4-11ed-ba43-dac502259ad0.png

二次探測法(開放地址法的一種)

a7c2781e-37c4-11ed-ba43-dac502259ad0.png

鏈地址法:鏈地址是對每一個同義詞都建一個單鏈表來解決沖突,HashMap采用的是這種方法;

aa7fe488-37c4-11ed-ba43-dac502259ad0.png

多重Hash法: 在key沖突的情況下多重hash,直到不沖突為止,這種方式不易產(chǎn)生堆積但是計算量太大;

公共溢出區(qū)法: 這種方式需要兩個表,一個存基礎(chǔ)數(shù)據(jù),另一個存放沖突數(shù)據(jù)稱為溢出表;

上面的圖片都是在網(wǎng)上找到的一些資料,和大學(xué)時學(xué)習(xí)時的差不多我就直接拿來用了;也當(dāng)自己復(fù)習(xí)了一遍;

介紹了那么多解決Hash沖突的方法,那ThreadLocalMap使用的哪一種方法呢?我們可以看一下源碼:

privatevoidset(ThreadLocalkey,Objectvalue){
Entry[]tab=table;
intlen=tab.length;
//根據(jù)HashCode&數(shù)組長度計算出數(shù)組該存放的位置
inti=key.threadLocalHashCode&(len-1);
//遍歷Entry數(shù)組中的元素
for(Entrye=tab[i];
e!=null;
e=tab[i=nextIndex(i,len)]){
ThreadLocalk=e.get();
//如果這個Entry對象的key正好是即將設(shè)置的key,那么就刷新Entry中的value;
if(k==key){
e.value=value;
return;
}
//entry!=null,key==null時,說明threadLcoal這key已經(jīng)被GC了,這里就是上面說到
//會有內(nèi)存泄露的地方,當(dāng)然作者也知道這種情況的存在,所以這里做了一個判斷進(jìn)行解決臟的
//entry(數(shù)組中不想存有過時的entry),但是也不能解決泄露問題,因為舊value還存在沒有消失
if(k==null){
//用當(dāng)前插入的值代替掉這個key為null的“臟”entry
replaceStaleEntry(key,value,i);
return;
}
}
//新建entry并插入table中i處
tab[i]=newEntry(key,value);
intsz=++size;
if(!cleanSomeSlots(i,sz)&&sz>=threshold)
rehash();
}

從這里我們可以看出使用的是線性探測的方式來解決hash沖突!

源碼中通過nextIndex(i, len)方法解決 hash 沖突的問題,該方法為((i + 1 < len) ? i + 1 : 0);,也就是不斷往后線性探測,直到找到一個空的位置,當(dāng)?shù)焦1砟┪驳臅r候還沒有找到空位置再從 0 開始找,成環(huán)形

使用ThreadLocal時對象存在哪里?

在java中,棧內(nèi)存歸屬于單個線程,每個線程都會有一個棧內(nèi)存,其存儲的變量只能在其所屬線程中可見,即棧內(nèi)存可以理解成線程的私有變量,而堆內(nèi)存中的變量對所有線程可見,可以被所有線程訪問!

那么ThreadLocal的實例以及它的值是不是存放在棧上呢?其實不是的,因為ThreadLocal的實例實際上也是被其創(chuàng)建的類持有,(更頂端應(yīng)該是被線程持有),而ThreadLocal的值其實也是被線程實例持有,它們都是位于堆上,只是通過一些技巧將可見性修改成了線程可見。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4968

    瀏覽量

    73960
  • spring
    +關(guān)注

    關(guān)注

    0

    文章

    341

    瀏覽量

    15935
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    509

    瀏覽量

    20826

原文標(biāo)題:ThreadLocal 你真的用不上嗎?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    Neway電機方案在電機控制的應(yīng)用場景

    Neway電機方案在電機控制的應(yīng)用場景Neway電機方案在電機控制領(lǐng)域的應(yīng)用場景廣泛且效果顯著,其核心優(yōu)勢在步進(jìn)電機、伺服電機控制及CNC機床主軸驅(qū)動等場景中得到了充分驗證。一、步進(jìn)電機與伺服電機
    發(fā)表于 01-04 10:10

    請問C語言中整形溢出對哪些應(yīng)用場景影響較大?

    C語言中整形溢出對哪些應(yīng)用場景影響較大
    發(fā)表于 12-24 08:24

    請問MOSFET在電源管理中有哪些應(yīng)用場景

    MOSFET在電源管理中有哪些應(yīng)用場景
    發(fā)表于 12-23 07:07

    Switch的應(yīng)用場景

    Switch的應(yīng)用場景如下: 調(diào)用一到多個函數(shù) 設(shè)置變量值或者返回一個值 執(zhí)行一到多個代碼片段 如果case標(biāo)簽很多,在switch的前兩個使用場景中,使用查找表可以更高效的完成。例如下面的兩種
    發(fā)表于 12-12 07:28

    藍(lán)牙網(wǎng)關(guān)是什么?都有哪些功能?應(yīng)用場景有哪些?

    點,更構(gòu)建起“設(shè)備互聯(lián)-數(shù)據(jù)流轉(zhuǎn)-智能管控”的完整鏈路,成為物聯(lián)網(wǎng)生態(tài)中不可或缺的核心組件。本文將系統(tǒng)解析藍(lán)牙網(wǎng)關(guān)的核心價值、技術(shù)架構(gòu)、應(yīng)用場景、現(xiàn)存挑戰(zhàn)及未來趨勢,為讀者呈現(xiàn)這一關(guān)鍵技術(shù)的全貌
    發(fā)表于 12-11 15:21

    CW32L083有哪些應(yīng)用場景

    CW32L083有哪些應(yīng)用場景
    發(fā)表于 11-24 07:37

    請問CW32L011有哪些應(yīng)用場景

    請問CW32L011有哪些應(yīng)用場景
    發(fā)表于 11-17 06:25

    CW32L0系列都有哪些應(yīng)用場景?有哪些優(yōu)勢?

    目前芯源的低功耗MCU比較火爆,就是CW32L0系列都有哪些應(yīng)用場景?有哪些優(yōu)勢?
    發(fā)表于 11-14 06:03

    合科泰電子元件的核心作用與應(yīng)用場景

    電阻,可適配消費電子、工業(yè)控制、戶外設(shè)備等多類場景。以下從元件分類、核心作用與應(yīng)用場景展開說明,為不同需求提供參考。
    的頭像 發(fā)表于 10-22 15:48 ?873次閱讀

    時統(tǒng)設(shè)備的應(yīng)用場景及功能作用

    時統(tǒng)設(shè)備是為各系統(tǒng)提供統(tǒng)一時間基準(zhǔn)和時間同步信號的設(shè)備,確保各設(shè)備和系統(tǒng)之間的協(xié)調(diào)運行以下是其常見的應(yīng)用場景及功能作用
    的頭像 發(fā)表于 06-23 17:07 ?661次閱讀

    UWB應(yīng)用場景

    鴻合智遠(yuǎn)|捷揚微-產(chǎn)品簡介介紹:UWB應(yīng)用場景
    的頭像 發(fā)表于 05-12 10:05 ?1030次閱讀
    UWB應(yīng)<b class='flag-5'>用場景</b>

    低溫冷凍機典型應(yīng)用場景以及操作大全

    低溫冷凍機在醫(yī)藥化工領(lǐng)域的應(yīng)用場景廣泛,其配套應(yīng)用和操作注意事項也具有一定的專業(yè)性。以下是對這些方面的詳細(xì)歸納:一、低溫冷凍機典型應(yīng)用場景1、藥品制造過程化學(xué)反應(yīng)控制:在原料藥的生產(chǎn)過程中,許多
    的頭像 發(fā)表于 04-14 13:55 ?928次閱讀
    低溫冷凍機典型應(yīng)<b class='flag-5'>用場景</b><b class='flag-5'>以及</b>操作大全

    取樣示波器的技術(shù)原理和應(yīng)用場景

    取樣示波器,也稱為采樣示波器,是一種重要的電子測量儀器,其技術(shù)原理和應(yīng)用場景可以歸納如下:技術(shù)原理取樣示波器的根本原理是利用等效取樣技術(shù),將周期性高頻(或高速)信號變換為與原來信號波形相似的低頻(或
    發(fā)表于 03-12 14:34

    頻域示波器的技術(shù)原理和應(yīng)用場景

    和掃描位置,以及處理和放大采集到的信號。 頻譜分析: 示波器通過FFT算法計算出信號的頻譜,并以圖形化的方式展示出來,便于用戶觀察和分析。 二、應(yīng)用場景 電子系統(tǒng)優(yōu)化: 在電子系統(tǒng)的設(shè)計和優(yōu)化
    發(fā)表于 03-11 14:37

    光頻譜分析儀的技術(shù)原理和應(yīng)用場景

    光頻譜分析儀是一種專為光信號的頻譜分析而設(shè)計的精密儀器,其技術(shù)原理和應(yīng)用場景如下:技術(shù)原理光頻譜分析儀的工作原理主要基于物質(zhì)與光之間的相互作用,特別是光通過物質(zhì)時產(chǎn)生的吸收、發(fā)射或散射現(xiàn)象。這些現(xiàn)象
    發(fā)表于 03-07 15:01