最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中ThreadLocal使用原理及Synchronized區(qū)別

 更新時(shí)間:2023年05月17日 11:22:42   作者:倔強(qiáng)的不服  
ThreadLocal叫做線程變量,本文詳細(xì)的介紹了ThreadLocal使用原理及Synchronized區(qū)別,有需要的朋友可以參考一下,希望對(duì)你有所幫助。

一、ThreadLocal簡(jiǎn)介

ThreadLocal叫做線程變量,意思是ThreadLocal中填充的變量屬于當(dāng)前線程,該變量對(duì)其他線程而言是隔離的,也就是說(shuō)該變量是當(dāng)前線程獨(dú)有的變量。ThreadLocal為變量在每個(gè)線程中都創(chuàng)建了一個(gè)副本,那么每個(gè)線程可以訪問(wèn)自己內(nèi)部的副本變量。

ThreadLoal 變量,線程局部變量,同一個(gè) ThreadLocal 所包含的對(duì)象,在不同的 Thread 中有不同的副本。這里有幾點(diǎn)需要注意:

  • 因?yàn)槊總€(gè) Thread 內(nèi)有自己的實(shí)例副本,且該副本只能由當(dāng)前 Thread 使用。這是也是 ThreadLocal 命名的由來(lái)。
  • 既然每個(gè) Thread 有自己的實(shí)例副本,且其它 Thread 不可訪問(wèn),那就不存在多線程間共享的問(wèn)題。

ThreadLocal 提供了線程本地的實(shí)例。它與普通變量的區(qū)別在于,每個(gè)使用該變量的線程都會(huì)初始化一個(gè)完全獨(dú)立的實(shí)例副本。ThreadLocal 變量通常被private static修飾。當(dāng)一個(gè)線程結(jié)束時(shí),它所使用的所有 ThreadLocal 相對(duì)的實(shí)例副本都可被回收。

總的來(lái)說(shuō),ThreadLocal 適用于每個(gè)線程需要自己獨(dú)立的實(shí)例且該實(shí)例需要在多個(gè)方法中被使用,也即變量在線程間隔離而在方法或類間共享的場(chǎng)景

下圖可以增強(qiáng)理解:

圖1-1  ThreadLocal在使用過(guò)程中狀態(tài)

二、ThreadLocal與Synchronized的區(qū)別

ThreadLocal<T>其實(shí)是與線程綁定的一個(gè)變量。ThreadLocal和Synchonized都用于解決多線程并發(fā)訪問(wèn)。

但是ThreadLocal與synchronized有本質(zhì)的區(qū)別:

1、Synchronized用于線程間的數(shù)據(jù)共享,而ThreadLocal則用于線程間的數(shù)據(jù)隔離。

2、Synchronized是利用鎖的機(jī)制,使變量或代碼塊在某一時(shí)該只能被一個(gè)線程訪問(wèn)。而ThreadLocal為每一個(gè)線程都提供了變量的副本,使得每個(gè)線程在某一時(shí)間訪問(wèn)到的并不是同一個(gè)對(duì)象,這樣就隔離了多個(gè)線程對(duì)數(shù)據(jù)的數(shù)據(jù)共享。

而Synchronized卻正好相反,它用于在多個(gè)線程間通信時(shí)能夠獲得數(shù)據(jù)共享。

一句話理解ThreadLocal,threadlocl是作為當(dāng)前線程中屬性ThreadLocalMap集合中的某一個(gè)Entry的key值Entry(threadlocl,value),雖然不同的線程之間threadlocal這個(gè)key值是一樣,但是不同的線程所擁有的ThreadLocalMap是獨(dú)一無(wú)二的,也就是不同的線程間同一個(gè)ThreadLocal(key)對(duì)應(yīng)存儲(chǔ)的值(value)不一樣,從而到達(dá)了線程間變量隔離的目的,但是在同一個(gè)線程中這個(gè)value變量地址是一樣的。

三、ThreadLocal的簡(jiǎn)單使用

直接上代碼:

public class ThreadLocaDemo {
    private static ThreadLocal<String> localVar = new ThreadLocal<String>();
    static void print(String str) {
        //打印當(dāng)前線程中本地內(nèi)存中本地變量的值
        System.out.println(str + " :" + localVar.get());
        //清除本地內(nèi)存中的本地變量
        localVar.remove();
    }
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            public void run() {
                ThreadLocaDemo.localVar.set("local_A");
                print("A");
                //打印本地變量
                System.out.println("after remove : " + localVar.get());
            }
        },"A").start();
        Thread.sleep(1000);
        new Thread(new Runnable() {
            public void run() {
                ThreadLocaDemo.localVar.set("local_B");
                print("B");
                System.out.println("after remove : " + localVar.get());
            }
        },"B").start();
    }
}
A :local_A
after remove : null
B :local_B
after remove : null

從這個(gè)示例中我們可以看到,兩個(gè)線程分表獲取了自己線程存放的變量,他們之間變量的獲取并不會(huì)錯(cuò)亂。這個(gè)的理解也可以結(jié)合圖1-1,相信會(huì)有一個(gè)更深刻的理解。

四、ThreadLocal的原理

要看原理那么就得從源碼看起。

4.1 ThreadLocal的set()方法:

 public void set(T value) {
        //1、獲取當(dāng)前線程
        Thread t = Thread.currentThread();
        //2、獲取線程中的屬性 threadLocalMap ,如果threadLocalMap 不為空,
        //則直接更新要保存的變量值,否則創(chuàng)建threadLocalMap,并賦值
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            // 初始化thradLocalMap 并賦值
            createMap(t, value);
    }

從上面的代碼可以看出,ThreadLocal  set賦值的時(shí)候首先會(huì)獲取當(dāng)前線程thread,并獲取thread線程中的ThreadLocalMap屬性。如果map屬性不為空,則直接更新value值,如果map為空,則實(shí)例化threadLocalMap,并將value值初始化。

那么ThreadLocalMap又是什么呢,還有createMap又是怎么做的,我們繼續(xù)往下看。大家最后自己再idea上跟下源碼,會(huì)有更深的認(rèn)識(shí)。

  static class ThreadLocalMap {
        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }

可看出ThreadLocalMap是ThreadLocal的內(nèi)部靜態(tài)類,而它的構(gòu)成主要是用Entry來(lái)保存數(shù)據(jù) ,而且還是繼承的弱引用。在Entry內(nèi)部使用ThreadLocal作為key,使用我們?cè)O(shè)置的value作為value。詳細(xì)內(nèi)容要大家自己去跟。

//這個(gè)是threadlocal 的內(nèi)部方法
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    //ThreadLocalMap 構(gòu)造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

4.2 ThreadLocal的get方法

    public T get() {
        //1、獲取當(dāng)前線程
        Thread t = Thread.currentThread();
        //2、獲取當(dāng)前線程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3、如果map數(shù)據(jù)不為空,
        if (map != null) {
            //3.1、獲取threalLocalMap中存儲(chǔ)的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果是數(shù)據(jù)為null,則初始化,初始化的結(jié)果,TheralLocalMap中存放key值為threadLocal,值為null
        return setInitialValue();
    }
private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

4.3 ThreadLocal的remove方法

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

 remove方法,直接將ThrealLocal 對(duì)應(yīng)的值從當(dāng)前相差Thread中的ThreadLocalMap中刪除。為什么要?jiǎng)h除,這涉及到內(nèi)存泄露的問(wèn)題。

實(shí)際上 ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用,弱引用的特點(diǎn)是,如果這個(gè)對(duì)象只存在弱引用,那么在下一次垃圾回收的時(shí)候必然會(huì)被清理掉。

所以如果 ThreadLocal 沒(méi)有被外部強(qiáng)引用的情況下,在垃圾回收的時(shí)候會(huì)被清理掉的,這樣一來(lái) ThreadLocalMap中使用這個(gè) ThreadLocal 的 key 也會(huì)被清理掉。但是,value 是強(qiáng)引用,不會(huì)被清理,這樣一來(lái)就會(huì)出現(xiàn) key 為 null 的 value。

ThreadLocal其實(shí)是與線程綁定的一個(gè)變量,如此就會(huì)出現(xiàn)一個(gè)問(wèn)題:如果沒(méi)有將ThreadLocal內(nèi)的變量刪除(remove)或替換,它的生命周期將會(huì)與線程共存。通常線程池中對(duì)線程管理都是采用線程復(fù)用的方法,在線程池中線程很難結(jié)束甚至于永遠(yuǎn)不會(huì)結(jié)束,這將意味著線程持續(xù)的時(shí)間將不可預(yù)測(cè),甚至與JVM的生命周期一致。舉個(gè)例字,如果ThreadLocal中直接或間接包裝了集合類或復(fù)雜對(duì)象,每次在同一個(gè)ThreadLocal中取出對(duì)象后,再對(duì)內(nèi)容做操作,那么內(nèi)部的集合類和復(fù)雜對(duì)象所占用的空間可能會(huì)開始持續(xù)膨脹。

 4.4、ThreadLocal與Thread,ThreadLocalMap之間的關(guān)系  

圖4-1 Thread、THreadLocal、ThreadLocalMap之間啊的數(shù)據(jù)關(guān)系圖

從這個(gè)圖中我們可以非常直觀的看出,ThreadLocalMap其實(shí)是Thread線程的一個(gè)屬性值,而ThreadLocal是維護(hù)ThreadLocalMap

這個(gè)屬性指的一個(gè)工具類。Thread線程可以擁有多個(gè)ThreadLocal維護(hù)的自己線程獨(dú)享的共享變量(這個(gè)共享變量只是針對(duì)自己線程里面共享)

五、ThreadLocal 常見使用場(chǎng)景

如上文所述,ThreadLocal 適用于如下兩種場(chǎng)景

1、每個(gè)線程需要有自己?jiǎn)为?dú)的實(shí)例

2、實(shí)例需要在多個(gè)方法中共享,但不希望被多線程共享

對(duì)于第一點(diǎn),每個(gè)線程擁有自己實(shí)例,實(shí)現(xiàn)它的方式很多。例如可以在線程內(nèi)部構(gòu)建一個(gè)單獨(dú)的實(shí)例。ThreadLoca 可以以非常方便的形式滿足該需求。

對(duì)于第二點(diǎn),可以在滿足第一點(diǎn)(每個(gè)線程有自己的實(shí)例)的條件下,通過(guò)方法間引用傳遞的形式實(shí)現(xiàn)。ThreadLocal 使得代碼耦合度更低,且實(shí)現(xiàn)更優(yōu)雅。

場(chǎng)景

1)存儲(chǔ)用戶Session

一個(gè)簡(jiǎn)單的用ThreadLocal來(lái)存儲(chǔ)Session的例子:

private static final ThreadLocal threadSession = new ThreadLocal();
    public static Session getSession() throws InfrastructureException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                s = getSessionFactory().openSession();
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
        return s;
    }

場(chǎng)景二、數(shù)據(jù)庫(kù)連接,處理數(shù)據(jù)庫(kù)事務(wù)

場(chǎng)景三、數(shù)據(jù)跨層傳遞(controller,service, dao)

每個(gè)線程內(nèi)需要保存類似于全局變量的信息(例如在攔截器中獲取的用戶信息),可以讓不同方法直接使用,避免參數(shù)傳遞的麻煩卻不想被多線程共享(因?yàn)椴煌€程獲取到的用戶信息不一樣)。

例如,用 ThreadLocal 保存一些業(yè)務(wù)內(nèi)容(用戶權(quán)限信息、從用戶系統(tǒng)獲取到的用戶名、用戶ID 等),這些信息在同一個(gè)線程內(nèi)相同,但是不同的線程使用的業(yè)務(wù)內(nèi)容是不相同的。

在線程生命周期內(nèi),都通過(guò)這個(gè)靜態(tài) ThreadLocal 實(shí)例的 get() 方法取得自己 set 過(guò)的那個(gè)對(duì)象,避免了將這個(gè)對(duì)象(如 user 對(duì)象)作為參數(shù)傳遞的麻煩。

比如說(shuō)我們是一個(gè)用戶系統(tǒng),那么當(dāng)一個(gè)請(qǐng)求進(jìn)來(lái)的時(shí)候,一個(gè)線程會(huì)負(fù)責(zé)執(zhí)行這個(gè)請(qǐng)求,然后這個(gè)請(qǐng)求就會(huì)依次調(diào)用service-1()、service-2()、service-3()、service-4(),這4個(gè)方法可能是分布在不同的類中的。這個(gè)例子和存儲(chǔ)session有些像。

package com.kong.threadlocal;
public class ThreadLocalDemo05 {
    public static void main(String[] args) {
        User user = new User("jack");
        new Service1().service1(user);
    }
}
class Service1 {
    public void service1(User user){
        //給ThreadLocal賦值,后續(xù)的服務(wù)直接通過(guò)ThreadLocal獲取就行了。
        UserContextHolder.holder.set(user);
        new Service2().service2();
    }
}
class Service2 {
    public void service2(){
        User user = UserContextHolder.holder.get();
        System.out.println("service2拿到的用戶:"+user.name);
        new Service3().service3();
    }
}
class Service3 {
    public void service3(){
        User user = UserContextHolder.holder.get();
        System.out.println("service3拿到的用戶:"+user.name);
        //在整個(gè)流程執(zhí)行完畢后,一定要執(zhí)行remove
        UserContextHolder.holder.remove();
    }
}
class UserContextHolder {
    //創(chuàng)建ThreadLocal保存User對(duì)象
    public static ThreadLocal<User> holder = new ThreadLocal<>();
}
class User {
    String name;
    public User(String name){
        this.name = name;
    }
}
執(zhí)行的結(jié)果:
service2拿到的用戶:jack
service3拿到的用戶:jack

場(chǎng)景四、Spring使用ThreadLocal解決線程安全問(wèn)題 

我們知道在一般情況下,只有無(wú)狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因?yàn)镾pring對(duì)一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全的“狀態(tài)性對(duì)象”采用ThreadLocal進(jìn)行封裝,讓它們也成為線程安全的“狀態(tài)性對(duì)象”,因此有狀態(tài)的Bean就能夠以singleton的方式在多線程中正常工作了。 

一般的Web應(yīng)用劃分為展現(xiàn)層、服務(wù)層和持久層三個(gè)層次,在不同的層中編寫對(duì)應(yīng)的邏輯,下層通過(guò)接口向上層開放功能調(diào)用。在一般情況下,從接收請(qǐng)求到返回響應(yīng)所經(jīng)過(guò)的所有程序調(diào)用都同屬于一個(gè)線程,如圖9-2所示。 

這樣用戶就可以根據(jù)需要,將一些非線程安全的變量以ThreadLocal存放,在同一次請(qǐng)求響應(yīng)的調(diào)用線程中,所有對(duì)象所訪問(wèn)的同一ThreadLocal變量都是當(dāng)前線程所綁定的。

下面的實(shí)例能夠體現(xiàn)Spring對(duì)有狀態(tài)Bean的改造思路:

代碼清單9-5  TopicDao:非線程安全

 
public class TopicDao {
   //①一個(gè)非線程安全的變量
   private Connection conn; 
   public void addTopic(){
        //②引用非線程安全變量
	   Statement stat = conn.createStatement();
	   …
   }

由于①處的conn是成員變量,因?yàn)閍ddTopic()方法是非線程安全的,必須在使用時(shí)創(chuàng)建一個(gè)新TopicDao實(shí)例(非singleton)。下面使用ThreadLocal對(duì)conn這個(gè)非線程安全的“狀態(tài)”進(jìn)行改造: 

代碼清單9-6  TopicDao:線程安全 

 
import java.sql.Connection;
import java.sql.Statement;
public class TopicDao {
  //①使用ThreadLocal保存Connection變量
private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();
public static Connection getConnection(){
	    //②如果connThreadLocal沒(méi)有本線程對(duì)應(yīng)的Connection創(chuàng)建一個(gè)新的Connection,
        //并將其保存到線程本地變量中。
if (connThreadLocal.get() == null) {
			Connection conn = ConnectionManager.getConnection();
			connThreadLocal.set(conn);
              return conn;
		}else{
              //③直接返回線程本地變量
			return connThreadLocal.get();
		}
	}
	public void addTopic() {
		//④從ThreadLocal中獲取線程對(duì)應(yīng)的
         Statement stat = getConnection().createStatement();
	}

不同的線程在使用TopicDao時(shí),先判斷connThreadLocal.get()是否為null,如果為null,則說(shuō)明當(dāng)前線程還沒(méi)有對(duì)應(yīng)的Connection對(duì)象,這時(shí)創(chuàng)建一個(gè)Connection對(duì)象并添加到本地線程變量中;如果不為null,則說(shuō)明當(dāng)前的線程已經(jīng)擁有了Connection對(duì)象,直接使用就可以了。這樣,就保證了不同的線程使用線程相關(guān)的Connection,而不會(huì)使用其他線程的Connection。因此,這個(gè)TopicDao就可以做到singleton共享了。 

當(dāng)然,這個(gè)例子本身很粗糙,將Connection的ThreadLocal直接放在Dao只能做到本Dao的多個(gè)方法共享Connection時(shí)不發(fā)生線程安全問(wèn)題,但無(wú)法和其他Dao共用同一個(gè)Connection,要做到同一事務(wù)多Dao共享同一個(gè)Connection,必須在一個(gè)共同的外部類使用ThreadLocal保存Connection。但這個(gè)實(shí)例基本上說(shuō)明了Spring對(duì)有狀態(tài)類線程安全化的解決思路。在本章后面的內(nèi)容中,我們將詳細(xì)說(shuō)明Spring如何通過(guò)ThreadLocal解決事務(wù)管理的問(wèn)題。

參考

ThreadLocal的應(yīng)用場(chǎng)景 - sw_kong - 博客園

百度安全驗(yàn)證

ThreadLocal使用場(chǎng)景分析 - 簡(jiǎn)書

ThreadLocal原理分析與使用場(chǎng)景 - 阿凡盧 - 博客園

ThreadLocal原理分析與使用場(chǎng)景 - 阿凡盧 - 博客園

ThreadLocal使用場(chǎng)景分析 - 簡(jiǎn)書

(轉(zhuǎn))spring里面對(duì)ThreadLocal的使用_迷茫之欲的博客-CSDN博客_spring threadlocal

到此這篇關(guān)于Java中ThreadLocal使用原理及Synchronized區(qū)別的文章就介紹到這了,更多相關(guān)Java ThreadLocal Synchronized 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • jdbc實(shí)現(xiàn)寵物商店管理系統(tǒng)

    jdbc實(shí)現(xiàn)寵物商店管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了jdbc實(shí)現(xiàn)寵物商店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • Java8中利用stream對(duì)map集合進(jìn)行過(guò)濾的方法

    Java8中利用stream對(duì)map集合進(jìn)行過(guò)濾的方法

    這篇文章主要給大家介紹了關(guān)于Java8中利用stream對(duì)map集合進(jìn)行過(guò)濾的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • 在Java生產(chǎn)環(huán)境下進(jìn)行性能監(jiān)控與調(diào)優(yōu)的詳細(xì)過(guò)程

    在Java生產(chǎn)環(huán)境下進(jìn)行性能監(jiān)控與調(diào)優(yōu)的詳細(xì)過(guò)程

    在Java生產(chǎn)環(huán)境下進(jìn)行性能監(jiān)控與調(diào)優(yōu)是一個(gè)復(fù)雜但重要的過(guò)程,它涉及到多個(gè)方面,包括代碼分析、JVM監(jiān)控、線程管理、垃圾收集優(yōu)化、內(nèi)存管理、數(shù)據(jù)庫(kù)交互等,下面我將提供一個(gè)詳細(xì)的概述和示例代碼,需要的朋友可以參考下
    2025-02-02
  • mybatis之foreach用法詳解

    mybatis之foreach用法詳解

    這篇文章主要介紹了mybatis之foreach用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • Java中JSON格式反序列化為Map且保證存取順序一致的問(wèn)題

    Java中JSON格式反序列化為Map且保證存取順序一致的問(wèn)題

    這篇文章主要介紹了Java中JSON格式反序列化為Map且保證存取順序一致的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • 詳解Spring Data操作Redis數(shù)據(jù)庫(kù)

    詳解Spring Data操作Redis數(shù)據(jù)庫(kù)

    Redis是一種NOSQL數(shù)據(jù)庫(kù),Key-Value形式對(duì)數(shù)據(jù)進(jìn)行存儲(chǔ),其中數(shù)據(jù)可以以內(nèi)存形式存在,也可以持久化到文件系統(tǒng)。Spring data對(duì)Redis進(jìn)行了很好的封裝,用起來(lái)也是十分的得心應(yīng)手,接下來(lái)通過(guò)本文給大家分享Spring Data操作Redis數(shù)據(jù)庫(kù),需要的朋友參考下
    2017-03-03
  • Java序列化JSON丟失精度問(wèn)題的解決方法(修復(fù)Long類型太長(zhǎng))

    Java序列化JSON丟失精度問(wèn)題的解決方法(修復(fù)Long類型太長(zhǎng))

    這篇文章主要給大家介紹了關(guān)于Java序列化JSON丟失精度問(wèn)題的解決方法,修復(fù)Long類型太長(zhǎng)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Java實(shí)現(xiàn)利用圖片或視頻生成GIF并發(fā)送微信

    Java實(shí)現(xiàn)利用圖片或視頻生成GIF并發(fā)送微信

    這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言如何利用圖片或視頻實(shí)現(xiàn)生成GIF并發(fā)送微信的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下
    2022-11-11
  • SpringBoot項(xiàng)目中Controller接收兩個(gè)實(shí)體的實(shí)現(xiàn)方法

    SpringBoot項(xiàng)目中Controller接收兩個(gè)實(shí)體的實(shí)現(xiàn)方法

    本文主要介紹了SpringBoot項(xiàng)目中Controller接收兩個(gè)實(shí)體的實(shí)現(xiàn)方法,主要介紹了兩種方法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 詳解springboot WebTestClient的使用

    詳解springboot WebTestClient的使用

    WebClient是一個(gè)響應(yīng)式客戶端,它提供了RestTemplate的替代方法。這篇文章主要介紹了詳解springboot WebTestClient的使用, 具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-11-11

最新評(píng)論

德化县| 巩义市| 莫力| 阳信县| 望谟县| 玛多县| 武邑县| 甘孜| 岳西县| 呼图壁县| 安泽县| 商丘市| 南靖县| 盐津县| 大庆市| 彭山县| 二手房| 兴安盟| 易门县| 金塔县| 抚宁县| 杭锦后旗| 北流市| 长岛县| 靖边县| 林西县| 咸阳市| 辽阳县| 彭阳县| 安仁县| 油尖旺区| 洛南县| 佛山市| 荔浦县| 莒南县| 保定市| 乐山市| 赤城县| 民县| 确山县| 南岸区|