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

徹底理解Java中的ThreadLocal

 更新時(shí)間:2017年03月09日 15:23:22   作者:楓之逆  
 ThreadLocal翻譯成中文比較準(zhǔn)確的叫法應(yīng)該是:線程局部變量。使用這個(gè)工具類可以很簡(jiǎn)潔地編寫出優(yōu)美的多線程程序。 接下來(lái)通過(guò)本文給大家介紹Java中的ThreadLocal,需要的朋友可以參考下

 ThreadLocal翻譯成中文比較準(zhǔn)確的叫法應(yīng)該是:線程局部變量。

 ThreadLocal是什么

  早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發(fā)問(wèn)題提供了一種新的思路。使用這個(gè)工具類可以很簡(jiǎn)潔地編寫出優(yōu)美的多線程程序。

  當(dāng)使用ThreadLocal維護(hù)變量時(shí),ThreadLocal為每個(gè)使用該變量的線程提供獨(dú)立的變量副本,所以每一個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響其它線程所對(duì)應(yīng)的副本。

  從線程的角度看,目標(biāo)變量就象是線程的本地變量,這也是類名中“Local”所要表達(dá)的意思。

  所以,在Java中編寫線程局部變量的代碼相對(duì)來(lái)說(shuō)要笨拙一些,因此造成線程局部變量沒(méi)有在Java開發(fā)者中得到很好的普及。

ThreadLocal的接口方法

  1. ThreadLocal類接口很簡(jiǎn)單,只有4個(gè)方法,我們先來(lái)了解一下:
  2. void set(Object value)設(shè)置當(dāng)前線程的線程局部變量的值。
  3. public Object get()該方法返回當(dāng)前線程所對(duì)應(yīng)的線程局部變量。
  4. public void remove()將當(dāng)前線程局部變量的值刪除,目的是為了減少內(nèi)存的占用,該方法是JDK 5.0新增的方法。需要指出的是,當(dāng)線程結(jié)束后,對(duì)應(yīng)該線程的局部變量將自動(dòng)被垃圾回收,所以顯式調(diào)用該方法清除線程的局部變量并不是必須的操作,但它可以加快內(nèi)存回收的速度。
  5. protected Object initialValue()返回該線程局部變量的初始值,該方法是一個(gè)protected的方法,顯然是為了讓子類覆蓋而設(shè)計(jì)的。這個(gè)方法是一個(gè)延遲調(diào)用方法,在線程第1次調(diào)用get()或set(Object)時(shí)才執(zhí)行,并且僅執(zhí)行1次。ThreadLocal中的缺省實(shí)現(xiàn)直接返回一個(gè)null。

  值得一提的是,在JDK5.0中,ThreadLocal已經(jīng)支持泛型,該類的類名已經(jīng)變?yōu)門hreadLocal<T>。API方法也相應(yīng)進(jìn)行了調(diào)整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。

  ThreadLocal是如何做到為每一個(gè)線程維護(hù)變量的副本的呢?其實(shí)實(shí)現(xiàn)的思路很簡(jiǎn)單:在ThreadLocal類中有一個(gè)Map,用于存儲(chǔ)每一個(gè)線程的變量副本,Map中元素的鍵為線程對(duì)象,而值對(duì)應(yīng)線程的變量副本。我們自己就可以提供一個(gè)簡(jiǎn)單的實(shí)現(xiàn)版本:

package com.test; 
public class TestNum { 
 // ①通過(guò)匿名內(nèi)部類覆蓋ThreadLocal的initialValue()方法,指定初始值 
 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { 
  public Integer initialValue() { 
   return 0; 
  } 
 }; 
 // ②獲取下一個(gè)序列值 
 public int getNextNum() { 
  seqNum.set(seqNum.get() + 1); 
  return seqNum.get(); 
 } 
 public static void main(String[] args) { 
  TestNum sn = new TestNum(); 
  // ③ 3個(gè)線程共享sn,各自產(chǎn)生序列號(hào) 
  TestClient t1 = new TestClient(sn); 
  TestClient t2 = new TestClient(sn); 
  TestClient t3 = new TestClient(sn); 
  t1.start(); 
  t2.start(); 
  t3.start(); 
 } 
 private static class TestClient extends Thread { 
  private TestNum sn; 
  public TestClient(TestNum sn) { 
   this.sn = sn; 
  } 
  public void run() { 
   for (int i = 0; i < 3; i++) { 
    // ④每個(gè)線程打出3個(gè)序列值 
    System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn[" 
       + sn.getNextNum() + "]"); 
   } 
  } 
 } 
} 

 通常我們通過(guò)匿名內(nèi)部類的方式定義ThreadLocal的子類,提供初始的變量值,如例子中①處所示。TestClient線程產(chǎn)生一組序列號(hào),在③處,我們生成3個(gè)TestClient,它們共享同一個(gè)TestNum實(shí)例。運(yùn)行以上代碼,在控制臺(tái)上輸出以下的結(jié)果:

thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-2] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-2] --> sn[3]

考察輸出的結(jié)果信息,我們發(fā)現(xiàn)每個(gè)線程所產(chǎn)生的序號(hào)雖然都共享同一個(gè)TestNum實(shí)例,但它們并沒(méi)有發(fā)生相互干擾的情況,而是各自產(chǎn)生獨(dú)立的序列號(hào),這是因?yàn)槲覀兺ㄟ^(guò)ThreadLocal為每一個(gè)線程提供了單獨(dú)的副本。

Thread同步機(jī)制的比較

  ThreadLocal和線程同步機(jī)制相比有什么優(yōu)勢(shì)呢?ThreadLocal和線程同步機(jī)制都是為了解決多線程中相同變量的訪問(wèn)沖突問(wèn)題。

  在同步機(jī)制中,通過(guò)對(duì)象的鎖機(jī)制保證同一時(shí)間只有一個(gè)線程訪問(wèn)變量。這時(shí)該變量是多個(gè)線程共享的,使用同步機(jī)制要求程序慎密地分析什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫,什么時(shí)候需要鎖定某個(gè)對(duì)象,什么時(shí)候釋放對(duì)象鎖等繁雜的問(wèn)題,程序設(shè)計(jì)和編寫難度相對(duì)較大。

  而ThreadLocal則從另一個(gè)角度來(lái)解決多線程的并發(fā)訪問(wèn)。ThreadLocal會(huì)為每一個(gè)線程提供一個(gè)獨(dú)立的變量副本,從而隔離了多個(gè)線程對(duì)數(shù)據(jù)的訪問(wèn)沖突。因?yàn)槊恳粋€(gè)線程都擁有自己的變量副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對(duì)象,在編寫多線程代碼時(shí),可以把不安全的變量封裝進(jìn)ThreadLocal。

  由于ThreadLocal中可以持有任何類型的對(duì)象,低版本JDK所提供的get()返回的是Object對(duì)象,需要強(qiáng)制類型轉(zhuǎn)換。但JDK 5.0通過(guò)泛型很好的解決了這個(gè)問(wèn)題,在一定程度地簡(jiǎn)化ThreadLocal的使用,代碼清單 9 2就使用了JDK 5.0新的ThreadLocal<T>版本。

  概括起來(lái)說(shuō),對(duì)于多線程資源共享的問(wèn)題,同步機(jī)制采用了“以時(shí)間換空間”的方式,而ThreadLocal采用了“以空間換時(shí)間”的方式。前者僅提供一份變量,讓不同的線程排隊(duì)訪問(wèn),而后者為每一個(gè)線程都提供了一份變量,因此可以同時(shí)訪問(wèn)而互不影響。

  spring使用ThreadLocal解決線程安全問(wèn)題我們知道在一般情況下,只有無(wú)狀態(tài)的Bean才可以在多線程環(huán)境下共享,在Spring中,絕大部分Bean都可以聲明為singleton作用域。就是因?yàn)镾pring對(duì)一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非線程安全狀態(tài)采用ThreadLocal進(jìn)行處理,讓它們也成為線程安全的狀態(tài),因?yàn)橛袪顟B(tài)的Bean就可以在多線程中共享了。

  一般的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所示:

通通透透理解ThreadLocal

通通透透理解ThreadLocal

  同一線程貫通三層這樣你就可以根據(jù)需要,將一些非線程安全的變量以ThreadLocal存放,在同一次請(qǐng)求響應(yīng)的調(diào)用線程中,所有關(guān)聯(lián)的對(duì)象引用到的都是同一個(gè)變量。

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

代碼清單3 TestDao:非線程安全

package com.test; 
import java.sql.Connection; 
import java.sql.SQLException; 
import java.sql.Statement; 
public class TestDao { 
 private Connection conn;// ①一個(gè)非線程安全的變量 
 public void addTopic() throws SQLException { 
  Statement stat = conn.createStatement();// ②引用非線程安全變量 
  // … 
 } 
} 

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

代碼清單4 TestDao:線程安全

package com.test; 
import java.sql.Connection; 
import java.sql.SQLException; 
import java.sql.Statement; 
public class TestDaoNew { 
 // ①使用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 = getConnection(); 
   connThreadLocal.set(conn); 
   return conn; 
  } else { 
   return connThreadLocal.get();// ③直接返回線程本地變量 
  } 
 } 
 public void addTopic() throws SQLException { 
  // ④從ThreadLocal中獲取線程對(duì)應(yīng)的Connection 
  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共享同一Connection,必須在一個(gè)共同的外部類使用ThreadLocal保存Connection。

ConnectionManager.java

package com.test; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
public class ConnectionManager { 
 private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { 
  @Override 
  protected Connection initialValue() { 
   Connection conn = null; 
   try { 
    conn = DriverManager.getConnection( 
      "jdbc:mysql://localhost:3306/test", "username", 
      "password"); 
   } catch (SQLException e) { 
    e.printStackTrace(); 
   } 
   return conn; 
  } 
 }; 
 public static Connection getConnection() { 
  return connectionHolder.get(); 
 } 
 public static void setConnection(Connection conn) { 
  connectionHolder.set(conn); 
 } 
} 

java.lang.ThreadLocal<T>的具體實(shí)現(xiàn)

那么到底ThreadLocal類是如何實(shí)現(xiàn)這種“為每個(gè)線程提供不同的變量拷貝”的呢?先來(lái)看一下ThreadLocal的set()方法的源碼是如何實(shí)現(xiàn)的:

/** 
 * Sets the current thread's copy of this thread-local variable 
 * to the specified value. Most subclasses will have no need to 
 * override this method, relying solely on the {@link #initialValue} 
 * method to set the values of thread-locals. 
 * 
 * @param value the value to be stored in the current thread's copy of 
 *  this thread-local. 
 */ 
 public void set(T value) { 
  Thread t = Thread.currentThread(); 
  ThreadLocalMap map = getMap(t); 
  if (map != null) 
   map.set(this, value); 
  else 
   createMap(t, value); 
 } 

在這個(gè)方法內(nèi)部我們看到,首先通過(guò)getMap(Thread t)方法獲取一個(gè)和當(dāng)前線程相關(guān)的ThreadLocalMap,然后將變量的值設(shè)置到這個(gè)ThreadLocalMap對(duì)象中,當(dāng)然如果獲取到的ThreadLocalMap對(duì)象為空,就通過(guò)createMap方法創(chuàng)建。

線程隔離的秘密,就在于ThreadLocalMap這個(gè)類。ThreadLocalMap是ThreadLocal類的一個(gè)靜態(tài)內(nèi)部類,它實(shí)現(xiàn)了鍵值對(duì)的設(shè)置和獲取(對(duì)比Map對(duì)象來(lái)理解),每個(gè)線程中都有一個(gè)獨(dú)立的ThreadLocalMap副本,它所存儲(chǔ)的值,只能被當(dāng)前線程讀取和修改。ThreadLocal類通過(guò)操作每一個(gè)線程特有的ThreadLocalMap副本,從而實(shí)現(xiàn)了變量訪問(wèn)在不同線程中的隔離。因?yàn)槊總€(gè)線程的變量都是自己特有的,完全不會(huì)有并發(fā)錯(cuò)誤。還有一點(diǎn)就是,ThreadLocalMap存儲(chǔ)的鍵值對(duì)中的鍵是this對(duì)象指向的ThreadLocal對(duì)象,而值就是你所設(shè)置的對(duì)象了。

為了加深理解,我們接著看上面代碼中出現(xiàn)的getMap和createMap方法的實(shí)現(xiàn):

/** 
 * Get the map associated with a ThreadLocal. Overridden in 
 * InheritableThreadLocal. 
 * 
 * @param t the current thread 
 * @return the map 
 */ 
ThreadLocalMap getMap(Thread t) { 
 return t.threadLocals; 
} 
/** 
 * Create the map associated with a ThreadLocal. Overridden in 
 * InheritableThreadLocal. 
 * 
 * @param t the current thread 
 * @param firstValue value for the initial entry of the map 
 * @param map the map to store. 
 */ 
void createMap(Thread t, T firstValue) { 
 t.threadLocals = new ThreadLocalMap(this, firstValue); 
} 

接下來(lái)再看一下ThreadLocal類中的get()方法:

/** 
 * Returns the value in the current thread's copy of this 
 * thread-local variable. If the variable has no value for the 
 * current thread, it is first initialized to the value returned 
 * by an invocation of the {@link #initialValue} method. 
 * 
 * @return the current thread's value of this thread-local 
 */ 
public T get() { 
 Thread t = Thread.currentThread(); 
 ThreadLocalMap map = getMap(t); 
 if (map != null) { 
  ThreadLocalMap.Entry e = map.getEntry(this); 
  if (e != null) 
   return (T)e.value; 
 } 
 return setInitialValue(); 
} 

再來(lái)看setInitialValue()方法:

/** 
 * Variant of set() to establish initialValue. Used instead 
 * of set() in case user has overridden the set() method. 
 * 
 * @return the initial value 
 */ 
 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; 
 } 

  獲取和當(dāng)前線程綁定的值時(shí),ThreadLocalMap對(duì)象是以this指向的ThreadLocal對(duì)象為鍵進(jìn)行查找的,這當(dāng)然和前面set()方法的代碼是相呼應(yīng)的。

  進(jìn)一步地,我們可以創(chuàng)建不同的ThreadLocal實(shí)例來(lái)實(shí)現(xiàn)多個(gè)變量在不同線程間的訪問(wèn)隔離,為什么可以這么做?因?yàn)椴煌腡hreadLocal對(duì)象作為不同鍵,當(dāng)然也可以在線程的ThreadLocalMap對(duì)象中設(shè)置不同的值了。通過(guò)ThreadLocal對(duì)象,在多線程中共享一個(gè)值和多個(gè)值的區(qū)別,就像你在一個(gè)HashMap對(duì)象中存儲(chǔ)一個(gè)鍵值對(duì)和多個(gè)鍵值對(duì)一樣,僅此而已。

小結(jié)

  ThreadLocal是解決線程安全問(wèn)題一個(gè)很好的思路,它通過(guò)為每個(gè)線程提供一個(gè)獨(dú)立的變量副本解決了變量并發(fā)訪問(wèn)的沖突問(wèn)題。在很多情況下,ThreadLocal比直接使用synchronized同步機(jī)制解決線程安全問(wèn)題更簡(jiǎn)單,更方便,且結(jié)果程序擁有更高的并發(fā)性。

ConnectionManager.java

package com.test; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
public class ConnectionManager { 
 private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { 
  @Override 
  protected Connection initialValue() { 
   Connection conn = null; 
   try { 
    conn = DriverManager.getConnection( 
      "jdbc:mysql://localhost:3306/test", "username", 
      "password"); 
   } catch (SQLException e) { 
    e.printStackTrace(); 
   } 
   return conn; 
  } 
 }; 
 public static Connection getConnection() { 
  return connectionHolder.get(); 
 } 
 public static void setConnection(Connection conn) { 
  connectionHolder.set(conn); 
 } 
} 

后記

  看到網(wǎng)友評(píng)論的很激烈,甚至關(guān)于ThreadLocalMap不是ThreadLocal里面的,而是Thread里面的這種評(píng)論都出現(xiàn)了,于是有了這個(gè)后記,下面先把jdk源碼貼上,源碼最有說(shuō)服力了。

/**  * ThreadLocalMap is a customized hash map suitable only for 
  * maintaining thread local values. No operations are exported 
  * outside of the ThreadLocal class. The class is package private to 
  * allow declaration of fields in class Thread. To help deal with 
  * very large and long-lived usages, the hash table entries use 
  * WeakReferences for keys. However, since reference queues are not 
  * used, stale entries are guaranteed to be removed only when 
  * the table starts running out of space. 
  */ 
 static class ThreadLocalMap {...} 

  源碼就是以上,這源碼自然是在ThreadLocal里面的,有截圖為證。

  本文是自己在學(xué)習(xí)ThreadLocal的時(shí)候,一時(shí)興起,深入看了源碼,思考了此類的作用、使用范圍,進(jìn)而聯(lián)想到對(duì)傳統(tǒng)的synchronize共享變量線程安全的問(wèn)題進(jìn)行比較,而總結(jié)的博文,總結(jié)一句話就是一個(gè)是鎖機(jī)制進(jìn)行時(shí)間換空間,一個(gè)是存儲(chǔ)拷貝進(jìn)行空間換時(shí)間。

以上所述是小編給大家介紹的徹底理解Java中的ThreadLocal,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽(tīng)與判斷的案例詳解

    Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽(tīng)與判斷的案例詳解

    這篇文章主要介紹了基于Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽(tīng)與判斷,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • Java內(nèi)部類持有外部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解

    Java內(nèi)部類持有外部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解

    這篇文章主要為大家詳細(xì)介紹了Java因?yàn)閮?nèi)部類持有外部類導(dǎo)致內(nèi)存泄露的原因以及其解決方案,文中的示例代碼講解詳細(xì),希望對(duì)大家有所幫助
    2022-11-11
  • idea2020.1無(wú)法自動(dòng)加載maven依賴的jar包問(wèn)題及解決方法

    idea2020.1無(wú)法自動(dòng)加載maven依賴的jar包問(wèn)題及解決方法

    這篇文章主要介紹了idea2020.1無(wú)法自動(dòng)加載maven依賴的jar包問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 詳解如何判斷Java線程池任務(wù)已執(zhí)行完

    詳解如何判斷Java線程池任務(wù)已執(zhí)行完

    線程池的使用并不復(fù)雜,麻煩的是如何判斷線程池中的任務(wù)已經(jīng)全部執(zhí)行完了,所以接下來(lái),我們就來(lái)看看如何判斷線程中的任務(wù)是否已經(jīng)全部執(zhí)行完吧
    2023-08-08
  • intellij idea旗艦版解決學(xué)生無(wú)法注冊(cè)問(wèn)題詳解

    intellij idea旗艦版解決學(xué)生無(wú)法注冊(cè)問(wèn)題詳解

    這篇文章主要介紹了intellij idea旗艦版解決學(xué)生無(wú)法注冊(cè)問(wèn)題詳解,文中通過(guò)圖文示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • SpringBoot實(shí)現(xiàn)application.yml文件敏感信息加密

    SpringBoot實(shí)現(xiàn)application.yml文件敏感信息加密

    本文主要介紹了SpringBoot實(shí)現(xiàn)application.yml文件敏感信息加密,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • Java List集合排序?qū)崿F(xiàn)方法解析

    Java List集合排序?qū)崿F(xiàn)方法解析

    這篇文章主要介紹了Java List集合排序?qū)崿F(xiàn)方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • java處理解析帶有反斜杠的json

    java處理解析帶有反斜杠的json

    在Java中操作JSON數(shù)據(jù)是一項(xiàng)常見(jiàn)的任務(wù),其中一個(gè)常見(jiàn)的問(wèn)題是如何在JSON字符串中包含反斜杠,本文主要介紹了java處理解析帶有反斜杠的json,感興趣的可以了解一下
    2024-01-01
  • Java 實(shí)例解析單例模式

    Java 實(shí)例解析單例模式

    單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式,這種模式涉及到一個(gè)單一的類,該類負(fù)責(zé)創(chuàng)建自己的對(duì)象,同時(shí)確保只有單個(gè)對(duì)象被創(chuàng)建
    2021-11-11
  • Java實(shí)現(xiàn)簡(jiǎn)單無(wú)界面五子棋

    Java實(shí)現(xiàn)簡(jiǎn)單無(wú)界面五子棋

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單無(wú)界面五子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05

最新評(píng)論

仪陇县| 平乡县| 肥乡县| 瑞安市| 临沭县| 大冶市| 清远市| 全州县| 张掖市| 叶城县| 应用必备| 泊头市| 庆阳市| 安西县| 惠东县| 灯塔市| 新营市| 轮台县| 肥东县| 克拉玛依市| 利辛县| 黄大仙区| 北碚区| 江北区| 大港区| 石狮市| 北宁市| 渝北区| SHOW| 饶平县| 文化| 东莞市| 乌兰县| 罗甸县| 抚松县| 达州市| 山丹县| 车致| 溧水县| 南木林县| 松溪县|